Generics Swift中T类型的泛型调用

Generics Swift中T类型的泛型调用,generics,swift,type-inference,Generics,Swift,Type Inference,在我的应用程序中,我想创建一个泛型方法,该方法创建一个依赖于给定类型T的对象数组 我创建了以下函数: func getArray<T : ROJSONObject>(key:String) -> T[] { var elements = T[]() for jsonValue in getValue(key).array! { var element = T() element.jsonData = jsonValue

在我的应用程序中,我想创建一个泛型方法,该方法创建一个依赖于给定类型T的对象数组

我创建了以下函数:

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
}
因此,我的解决方案是定义一个包含T类型实例的附加参数,以便它自动检测该类型:

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
}

因此,不管怎样,该类型始终是基本类型,即使我已将
指定为
关键字。我知道这个例子没有多大意义,但它只是为了测试的目的。

你应该能够用
作为
关键字指示类型:
object.getArray(“key”)作为Document[]
我认为这是一个bug

您可以通过使类成为
NSObject
的子类或使用
@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)
导入可可粉
A类:NSObject{
init(){}
}
B类:A{}
C类:A{}
func Create()->T{
返回T()
}
println(创建()作为
println(创建()为B)
println(创建()为C)
//
//
//
D类{
@必需的init(){}
}
E类:D类{
init(){}
}
F类:D类{
init(){}
}
func Create2()->T{
返回T()
}
println(Create2()作为D)
println(Create2()作为E)
println(Create2()作为F)
//C11lldb_expr_01D(有0个子项)
//C11lldb_expr_01E(有一个孩子)
//C11lldb_expr_01F(有一个孩子)

不确定为什么
@required
解决问题。但是

必需的

将此属性应用于指定的或方便的 类的初始值设定项,指示每个子类必须实现 那个初始化器

必须明确实现所需的指定初始值设定项。 所需的方便初始值设定项可以显式实现 或者在子类直接实现所有 超类的指定初始值设定项(或当子类重写时 指定的初始值设定人(带有方便的初始值设定人)


我通过借用swift运行时函数
unsafeBitCast
解决了这个问题

它被声明为
func unsafeBitCast(x:T,\uu:U.Type)->U
,您可以将其称为
unsafeBitCast(value,MyType)

应用于您的函数,这将是

func getArray<T : ROJSONObject>(key:String, _: T.Type) -> T[] {
    // function stays the same
}

您需要使初始值设定项
成为必需的
,然后添加
让realType=T.self
行,并将
T()
替换为
realType()

班级人员{
必需的init(){}
func getWorkingHours()->Float{
返回40.0
}
}
班长:人{
覆盖func getWorkingHours()->Float{
println(100.0)
返回100.0
}
}
班主任:人{
覆盖func getWorkingHours()->Float{
println(42.0)
返回42.0
}
}
func getWorkingHours()->T{
让realType=T.self
var person=realType()
person.getWorkingHours()
返回人
}

回答问题的第一部分

您无需向该方法添加附加参数来指定
T
的类型,因为您已经将
[T]
作为返回类型

所以你换了这条线

object.getArray<Document>("key")
这样,您就有机会将类型指定为
T

不要这样称呼它

object.getArray<Document>("key")

为我解决了这个问题。

问题中代码的工作版本(第二部分)

•由于函数返回泛型人员类型,因此需要Init(
newPerson(作为person:T)->T

•我已将类方法
func getWorkingHours()
替换为
var workingHours{get}
。。它以更“快速”的方式同样有效

getWorkingHours()
返回小时,如名称所示,而不是一个人

class Person {
    required init() {}
    var workingHours: Float { get { return 40 } }
}

class Boss : Person {
    override var workingHours: Float { get { return 100 } }
}

class Worker : Person {
    override var workingHours: Float { get { return 42 } }
}

func getWorkingHours<T : Person>(_ person: T) -> Float {
    return person.workingHours
}

func newPerson<T : Person>(as person: T) -> T {
    return T()
}

// -----------------------------------------------

let worker = Worker()
let boss = Boss()

print( getWorkingHours(worker) ) // prints 42.0
print( getWorkingHours(boss) ) // prints 100.0

let person = newPersonOfSameClass(as: worker)

print( getWorkingHours(person) ) // prints 42.0
班级人员{
必需的init(){}
var workingHours:Float{get{return 40}
}
班长:人{
重写var workingHours:Float{get{return 100}
}
班主任:人{
重写var workingHours:Float{get{return 42}
}
func getWorkingHours(uu-person:T)->Float{
返回人员工作时间
}
func newPerson(作为person:T)->T{
返回T()
}
// -----------------------------------------------
让worker=worker()
让boss=boss()
打印(getWorkingHours(worker))//打印42.0
打印(getWorkingHours(boss))//打印100.0
let person=newPersonOfSameClass(as:worker)
打印(getWorkingHours(person))//打印42.0

希望能有帮助。。此代码已准备好在操场上复制/粘贴。

谢谢您的回答。我编辑了我的问题并尝试了你的解决方案。但不知何故,它总是停留在基类上,并没有用关键字“AS”在内部创建一个被指定类的对象。我现在不能做更多的测试,但是你可以考虑。我提交了一个bug报告。让我们看看苹果的反应。当我得到答案时,我会把它贴在这里。通常需要很长时间才能回复,但提交报告仍然是一个好主意:)哦,没有Swift类型的系统被完全破坏(再一次)。此外,若基类是从NSObject继承的,那个么它也“起作用”。答案很简单。您必须以某种方式指定类型,以便将其作为
object.getArray(“key”)作为[Document]
谢谢,使用@required我可以解决我的问题!我认为只有当泛型函数接收到多个参数时,正确的调用才会是getArray(“key”,Document.self)。如果它只需要一个参数就可以传递document,这太奇怪了,你需要像这样传递它作为一个参数。从可读性的角度来看,getArray更有意义。不过这很管用,谢谢!GETRART是C++风格。不快。swift从应用函数的对象中知道类型。调用object.getArray(key:“your key”)时,将使用对象的类型。
getArray("key", Document)
class Person {
    required 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 {
    let realType = T.self
    var person = realType()
    person.getWorkingHours()

    return person
}
object.getArray<Document>("key")
object.getArray("key") as [Document]
object.getArray<Document>("key")
object.getArray("key")
class Person {
    required init() {}
    var workingHours: Float { get { return 40 } }
}

class Boss : Person {
    override var workingHours: Float { get { return 100 } }
}

class Worker : Person {
    override var workingHours: Float { get { return 42 } }
}

func getWorkingHours<T : Person>(_ person: T) -> Float {
    return person.workingHours
}

func newPerson<T : Person>(as person: T) -> T {
    return T()
}

// -----------------------------------------------

let worker = Worker()
let boss = Boss()

print( getWorkingHours(worker) ) // prints 42.0
print( getWorkingHours(boss) ) // prints 100.0

let person = newPersonOfSameClass(as: worker)

print( getWorkingHours(person) ) // prints 42.0