在泛型中使用类型变量

sud*_*udo 20 generics swift

我有这个问题,除了Swift.如何Type在泛型中使用变量?

我试过这个:

func intType() -> Int.Type {
    return Int.self
}

func test() {
    var t = self.intType()
    var arr = Array<t>() // Error: "'t' is not a type". Uh... yeah, it is.
}
Run Code Online (Sandbox Code Playgroud)

这也不起作用:

var arr = Array<t.Type>() // Error: "'t' is not a type"
var arr = Array<t.self>() // Swift doesn't seem to even understand this syntax at all.
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点?我觉得Swift不支持它并且给我一些含糊不清的错误信息.

编辑:这是一个更复杂的例子,使用通用函数头无法规避问题.当然它没有意义,但我在我的代码中的某个地方明智地使用了这种功能,而宁愿发布一个干净的例子而不是我的实际代码:

func someTypes() -> [Any.Type] {
    var ret = [Any.Type]()
    for (var i = 0; i<rand()%10; i++) {
        if (rand()%2 == 0){ ret.append(Int.self) }
        else {ret.append(String.self) }
    }
    return ret
}

func test() {
    var ts = self.someTypes()

    for t in ts {
        var arr = Array<t>()
    }
}
Run Code Online (Sandbox Code Playgroud)

jtb*_*des 26

Swift的静态类型意味着必须在编译时知道变量的类型.

在泛型函数的上下文中func foo<T>() { ... },T看起来像一个变量,但它的类型实际上是在编译时基于调用函数的位置而知道的.行为Array<T>()取决于T,但此信息在编译时已知的.

使用协议时,Swift采用动态调度,因此您可以编写Array<MyProtocol>(),并且数组只是存储对实现的内容的引用MyProtocol- 因此当您从数组中获取某些内容时,您可以访问所需的所有函数/变量/类型MyProtocol.

但是,如果t实际上是一个类型的变量Any.Type,Array<t>()则没有意义,因为它的类型在编译时实际上是未知的.(由于它Array是一个通用结构,编译器需要知道哪个类型用作泛型参数,但这是不可能的.)

我建议今年观看WWDC的一些视频:

我发现这张幻灯片特别有助于理解协议和动态调度:


Lau*_*ent 6

有一种方法,它被称为泛型.你可以做那样的事情.

class func foo() {
    test(Int.self)
}

class func test<T>(t: T.Type) {
    var arr = Array<T>()
}
Run Code Online (Sandbox Code Playgroud)

您将需要以某种方式提示您想要专门化该函数的类型的编译器.另一种方法是使用return param(在这种情况下被丢弃):

class func foo() {
    let _:Int = test()
}

class func test<T>() -> T {
    var arr = Array<T>()
}
Run Code Online (Sandbox Code Playgroud)

在类(或结构)上使用泛型,您不需要额外的参数:

class Whatever<T> {
    var array = [T]() // another way to init the array.
}

let we = Whatever<Int>()
Run Code Online (Sandbox Code Playgroud)


Aar*_*ger 5

jtbandes 的回答 - 您不能使用当前的方法,因为 Swift 是静态类型的 - 是正确的。

但是,如果您愿意在数组中创建允许类型的白名单,例如在 中enum,您可以在运行时动态初始化不同的类型。

首先,创建一个enum允许的类型:

enum Types {
    case Int
    case String
}
Run Code Online (Sandbox Code Playgroud)

创建一个Example类。实现您的someTypes()函数以使用这些枚举值。(您可以轻松地将字符串的 JSON 数组转换为该枚举的数组。)

class Example {
    func someTypes() -> [Types] {
        var ret = [Types]()
        for _ in 1...rand()%10 {
            if (rand()%2 == 0){ ret.append(.Int) }
            else {ret.append(.String) }
        }
        return ret
    }
Run Code Online (Sandbox Code Playgroud)

现在实现您的测试功能,使用switcharr限定每个允许的类型:

    func test() {
        let types = self.someTypes()

        for type in types {
            switch type {
            case .Int:
                var arr = [Int]()
                arr += [4]

            case .String:
                var arr = [String]()
                arr += ["hi"]
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能知道,您也可以声明arr[Any]混合类型(jtbandes 回答中的“异构”情况):

var arr = [Any]()

for type in types {
    switch type {
    case .Int:
        arr += [4]

    case .String:
        arr += ["hi"]
    }
}

print(arr)
Run Code Online (Sandbox Code Playgroud)