除了Swift,我有this question。如何在通用中使用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.
}
这也不起作用:
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.
有办法做到这一点吗?我觉得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>()
}
}
答案 0 :(得分:26)
Swift的static typing表示必须在编译时知道变量的类型。
在泛型函数func foo<T>() { ... }
的上下文中, T 看起来像一个变量,但其类型实际上是在编译时根据函数从< / em>的。 Array<T>()
的行为取决于T
,但此信息 在编译时已知。
使用协议时,Swift使用动态调度,因此您可以编写Array<MyProtocol>()
,并且数组只存储对实现MyProtocol
的内容的引用 - 所以当您获得某些内容时在数组之外,您可以访问MyProtocol
所需的所有函数/变量/类型。
但如果t
实际上是类Any.Type
的变量,则Array<t>()
没有意义,因为它的类型在编译时实际上是未知的。 (由于Array
是一个通用结构,编译器需要知道哪个类型用作泛型参数,但这是不可能的。)
我建议今年观看WWDC的一些视频:
我发现这张幻灯片特别有助于理解协议和动态调度:
答案 1 :(得分:6)
有一种方法,它被称为泛型。你可以这样做。
class func foo() {
test(Int.self)
}
class func test<T>(t: T.Type) {
var arr = Array<T>()
}
您需要以某种方式提示您想要专门化该函数的类型的编译器。另一种方法是使用return param(在这种情况下被丢弃):
class func foo() {
let _:Int = test()
}
class func test<T>() -> T {
var arr = Array<T>()
}
在类(或结构)上使用泛型,你不需要额外的参数:
class Whatever<T> {
var array = [T]() // another way to init the array.
}
let we = Whatever<Int>()
答案 2 :(得分:4)
jtbandes&#39;回答 - 您无法使用当前的方法,因为Swift是静态类型的 - 是正确的。
但是,如果您愿意在数组中创建允许类型的白名单,例如在funcYgivenX
中,则可以在运行时动态初始化不同类型。
首先,创建一个允许类型的enum
:
enum
创建enum Types {
case Int
case String
}
课程。实现Example
函数以使用这些枚举值。 (您可以轻松地将JSON字符串数组转换为此枚举的数组。)
someTypes()
现在使用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
正如您所知,您也可以将 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
以混合类型(&#34;异性&#34;案例在jtbandes&#39;答案中):
[Any]
答案 3 :(得分:3)
我会用你从第一个答案中学到的东西来分解它。我冒昧地重构了一些代码。这是:
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)
}
}
这有点奏效,但我相信这样做非常不正统。你能用反射(镜像)吗?
答案 4 :(得分:0)
有可能,只要您可以向编译器提供有关... T
类型的“提示”。因此,在下面的示例中,必须使用: String?
。
func cast<T>(_ value: Any) -> T? {
return value as? T
}
let inputValue: Any = "this is a test"
let casted: String? = cast(inputValue)
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
为什么Swift不仅允许我们let casted = cast<String>(inputValue)
我永远不会知道。
一个烦人的场景是当您的函数没有返回值时。然后,它不一定总是提供必要的“提示”。让我们来看这个例子...
func asyncCast<T>(_ value: Any, completion: (T?) -> Void) {
completion(value as? T)
}
以下客户端代码未编译。它给出了“无法推断通用参数'T'”错误。
let inputValue: Any = "this is a test"
asyncCast(inputValue) { casted in
print(casted)
print(type(of: casted))
}
但是您可以通过向编译器提供“提示”来解决此问题,如下所示:
asyncCast(inputValue) { (casted: String?) in
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
}