关于swift:在Generic中使用Type变量

Using a Type Variable in a Generic

我有这个问题,除了斯威夫特。如何在泛型中使用Type变量?

我试过这个:

1
2
3
4
5
6
7
8
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.
}

这也不起作用:

1
2
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.

有办法吗?我有种感觉,斯威夫特只是不支持它,并给了我一些模棱两可的错误信息。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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>()
    }
}

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

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

在使用协议时,swift采用动态调度,因此您可以编写Array(),数组只存储实现MyProtocol的对象的引用,因此当您从数组中获得某些内容时,您可以访问MyProtocol所需的所有函数/变量/类型别名。

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

我建议今年观看世界野生动物保护协会的一些视频:

  • SWIFT中面向协议的程序设计
  • 在Swift中构建具有价值类型的更好的应用程序

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

></P></p>
<div class=


有一种方法叫仿制药。你可以这样做。

1
2
3
4
5
6
7
class func foo() {
    test(Int.self)
}

class func test<T>(t: T.Type) {
    var arr = Array<T>()
}

您将需要提示编译器您希望用某种方式专门化函数的类型。另一种方法是使用返回参数(在这种情况下丢弃):

1
2
3
4
5
6
7
class func foo() {
    let _:Int = test()
}

class func test<T>() -> T {
    var arr = Array<T>()
}

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

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

let we = Whatever<Int>()


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

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

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

1
2
3
4
enum Types {
    case Int
    case String
}

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

1
2
3
4
5
6
7
8
9
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
    }

现在,使用switch来实现您的测试功能,将arr范围扩展到每个允许的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    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"]
            }
        }
    }
}

如您所知,您也可以将arr声明为[Any],以混合类型(jtbandes答案中的"异质"情况):

1
2
3
4
5
6
7
8
9
10
11
12
13
var arr = [Any]()

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

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

print(arr)

我会用你从第一个答案中学到的东西来分解它。我冒昧地重构了一些代码。这里是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func someTypes<T>(t: T.Type) -> [Any.Type] {
    var ret = [Any.Type]()
    for _ in 0..<rand()%10 {
        if (rand()%2 == 0){ ret.append(T.self) }
        else {
            ret.append(String.self)
        }
    }
    return ret
}


func makeArray<T>(t: T) -> [T] {
    return [T]()
}

func test() {
    let ts = someTypes(Int.self)
    for t in ts {
        print(t)
    }
}

这有点奏效,但我相信这样做的方式非常不正统。你能用反射(镜像)代替吗?