泛型在Swift中使用Type T调用 [英] Generics call with Type T in Swift

查看:90
本文介绍了泛型在Swift中使用Type T调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我想创建一个泛型方法,它创建一个对象数组,并根据给定的类型T创建一个对象数组。我创建了以下函数:

  func getArray< T:ROJSONObject>(key:String) - >对于getValue(key).array中的jsonValue,T [] {
var elements = T []()

! {
var element = T()

element.jsonData = jsonValue
elements.append(element)
}

返回元素
}

现在我想在调用方法时传递该类型,所以它知道它应该在内部创建它的类型。我认为在Java和C#中你可以使用类似的方法:

pre $ object $ object $ getArray< Document>(key)

当我这样称呼它时,我总是得到错误:

 不能明确地专用一个通用函数

所以我的解决方法是定义一个包含T类型实例的附加参数,以便它自动检测类型:

  func getArray< ; T:ROJSONObject>(key:String,type:T) - >对于getValue(key).array中的jsonValue,T [] {
var elements = T []()

! {
var element = T()

element.jsonData = jsonValue
elements.append(element)
}

返回元素
}

真的没有其他方法可以在不传递未使用的实例的情况下获得该行为吗?或者我误吞东西?



进一步测试



在jtbandes我做了更多的测试。我尝试通过在调用中添加作为来强制使用Type。

  class Person {

init(){}

func getWorkingHours() - > Float {
return 40.0
}
}

class Boss:Person {
override func getWorkingHours() - > Float {
println(100.0)
return 100.0
}
}

类Worker:Person {
覆盖func getWorkingHours() - > ; Float {
println(42.0)
return 42.0
}
}

func getWorkingHours< T:Person>() - > T {
var person = T()
person.getWorkingHours()

return person
}

var worker:Worker = getWorkingHours ()as Worker
var boss:Boss = getWorkingHours()as Boss
worker.getWorkingHours()//输出40.0而不是42.0
boss.getWorkingHours()//输出40.0代替100.0

因此,类型总是基本类型,即使我已经用作为关键字。我知道这个例子没有多大意义,但它只是为了测试目的。

解决方案

我认为这是一个bug 。



你可以通过使类成为 NSObject 的子类或者用基类的标记构造函数来解决它 @required

  import Cocoa 

class A:NSObject {
init(){}
}
class B:A {} $ b $ class class C:A {}

func Create< T :NSObject的> () - > T {
return T()
}

println(Create()as A)
println(Create()as B)
println(Create ()as C)

//< _TtC11lldb_expr_01A:0x7f85ab717bc0>
//< _TtC11lldb_expr_01B:0x7f85ab451e00>
//< _TtC11lldb_expr_01C:0x7f85ab509160>

class D {
@required init(){}
}

class E:D {
init(){}


class F:D {
init(){}
}

func Create2< T:D> () - > T {
return T()
}

println(Create2()as D)
println(Create2()as E)
println(Create2 ()as F)

// C11lldb_expr_01D(有0个孩子)
// C11lldb_expr_01E(有1个孩子)
// C11lldb_expr_01F(有1个孩子)






不知道为什么 @required 解决问题。但这是参考资料


必填



将此属性应用于类的指定或便利
初始值设定项,以指示每个子类必须实现
初始值设定项。



必需的指定初始值设定项必须明确实施。
所需的便利初始值设定项既可以显式实现
,也可以在子类直接实现所有
超类的指定初始值设定项时继承(或者当子类使用便捷初始值设定项覆盖
指定初始值设定项时) 。


In my application I want to create an generic method which creates an array of object depening on the given type T.

I created the following function:

func getArray<T : ROJSONObject>(key:String) -> T[] {
    var elements = T[]()

    for jsonValue in getValue(key).array! {
        var element = T()

        element.jsonData = jsonValue
        elements.append(element)
    }

    return elements
}

Now I want to pass the type when I call the method, so it does know which type it should create internally. I think in Java and C# you can use a method like that:

object.getArray<Document>("key")

When I call it like that, I always get the error:

Cannot explicitly specialize a generic function

So my fix was to define an additional parameter containing an instance of the type T so it does automatically detect the type:

func getArray<T : ROJSONObject>(key:String, type:T) -> T[] {
    var elements = T[]()

    for jsonValue in getValue(key).array! {
        var element = T()

        element.jsonData = jsonValue
        elements.append(element)
    }

    return elements
}

Is there really no other way to get that behaviour without passing an unused instance? Or am I misunterstanding something?

Further Testing

After the answer of jtbandes I did some more testing. I tried to force the Type by adding the as in the call.

class Person {

    init() { }

    func getWorkingHours() -> Float {
        return 40.0
    }
}

class Boss : Person {
    override func getWorkingHours() -> Float {
        println(100.0)
        return 100.0
    }
}

class Worker : Person {
    override func getWorkingHours() -> Float {
        println(42.0)
        return 42.0
    }
}

func getWorkingHours<T : Person>() -> T {
    var person = T()
    person.getWorkingHours()

    return person
}

var worker:Worker = getWorkingHours() as Worker
var boss:Boss = getWorkingHours() as Boss
worker.getWorkingHours() // prints out 40.0 instead of 42.0
boss.getWorkingHours() // prints out 40.0 instead of 100.0

So somehow the type is always the base type even I've specified the type with the as keyword. I know the example does not make much sense, but it was just for testing purpose..

解决方案

I think it is a bug.

You can work around it by making the class a sub-class of NSObject or mark constructor of base class with @required

import Cocoa

class A : NSObject {
    init() { }
}
class B : A {}
class C : A {}

func Create<T:NSObject> () -> T {
    return T()
}

println(Create() as A)
println(Create() as B)
println(Create() as C)

//<_TtC11lldb_expr_01A: 0x7f85ab717bc0>
//<_TtC11lldb_expr_01B: 0x7f85ab451e00>
//<_TtC11lldb_expr_01C: 0x7f85ab509160>

class D {
    @required init() { } 
}

class E : D {
    init() { }
}

class F : D {
    init() { }
}

func Create2<T:D> () -> T {
    return T()
}

println(Create2() as D)
println(Create2() as E)
println(Create2() as F)

//C11lldb_expr_01D (has 0 children)
//C11lldb_expr_01E (has 1 child)
//C11lldb_expr_01F (has 1 child)


Not sure why @required solve the problem. But this is the reference

required

Apply this attribute to a designated or convenience initializer of a class to indicate that every subclass must implement that initializer.

Required designated initializers must be implemented explicitly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or when the subclass overrides the designated initializers with convenience initializers).

这篇关于泛型在Swift中使用Type T调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆