Ale*_*lex 2 generics collections struct swift
我在Swift中遇到了一些泛型问题.我有一个通用的结构:
struct MyStruct<T> { ... }
Run Code Online (Sandbox Code Playgroud)
我想将它存储在一个集合中(在本例中是一个字典):
var myStructDict = [MyKeyType: MyStruct]()
Run Code Online (Sandbox Code Playgroud)
你会注意到我没有指定Tfor 的类型MyStruct.那是因为我想存储任何MyStruct类型,独立于类型T.
好吧,你说,Any用于T([MyKeyType: MyStruct<Any>]).是的,但我也想保持原来的类型信息,T每个结构的,当我从词典中,这样当需要一个功能得到结构MyStruct被调用时,它被称为与权利类型T.
这是一个例子:
// Setup
var myStructDict: [String: MyStruct<Any>]
func f(v: MyStruct<String>) { ... }
func f(v: MyStruct<Int>) { ... }
// Set value
let s1 = MyStruct<String>(...)
myStructDict["key"] = unsafeTypeCast(s, MyStruct<Any>.self)
// Get value
let s2 = myStructDict["key"]
// Call function
f(s2) // I want the function that takes a `MyStruct<String>` to be called
Run Code Online (Sandbox Code Playgroud)
我保证每种类型T都会有一个功能.
我可以使用允许的每种类型的switch语句,如下所示:
switch s1 {
case let v as MyStruct<String>: f(v)
...
}
Run Code Online (Sandbox Code Playgroud)
但这根本不是一个好主意,因为Any,嗯......,是任何类型.
通用类型不会在Swift中统一.MyStruct<Int>并且MyStruct<String>是完全不同的类型,简直是Int和String是,不管他们多么相似的样子.这是类型保留泛型系统的属性之一(与您在Java中找到的类型擦除泛型系统相反).
不同种类的泛型系统可用于不同的事物.类型保留泛型是最好的,当你开始专业化并按照更通用的代码工作时 - 即编写符合协议的特定类型,然后编写使用这些协议的泛型函数或类型,或使用泛型创建可包含的包装类型其他类型的价值观,而不关心这些类型是什么.
另一方面,需要从泛型类型返回到内部专用类型或尝试创建相关泛型类型的泛化的用例可能不那么简单.
你在寻找什么需要两个部分:
MyStruct<String>并MyStruct<Int>具有公共类型祖先的方法,因此您可以将所述类型声明为字典中的元素类型MyStruct你从字典中拉出来的基于特殊类型的调度的方法不要一概而论的类型参数,概括了整个类型:那就是,不要让一个字典[MyKeyType: MyStruct<Any>],使一本字典[MyKeyType: MyValueType],其中MyValueType是一个协议,这既MyStruct<Int>和MyStruct<String>一致.(你可以使用Any你的值类型,但是你会在你的字典中得到不是MyStructs的东西.)例如:
protocol MyType {
func doNothing()
}
struct MyStruct<T>: MyType {
let thing: T
func doNothing() {}
}
let a = MyStruct(thing: "Hello")
let b = MyStruct(thing: 1)
let dict: [String: MyType] = ["a": a, "b": b]
Run Code Online (Sandbox Code Playgroud)
这个doNothing函数有一个奇怪的地方.我们不能让构件thing是所述协议的要求,即分离MyValueType自Any,因为该成员的类型是通用的-和具有相关联型需求的协议不能被用作一个具体类型(例如,作为字典的元件类型的声明) .大概你真正MyStruct做的不仅仅是持有一个泛型thing,所以也许你可以使用该类型的其他一些独特的功能来创建一个只有它符合的协议.
我保证每种类型
T都会有一个功能.
说出你想要的一切,但是编译器有它的手指并且没有听.换句话说,这是一个"保证",你不能用语言强制执行,所以Swift不会让你做那些从这个假设出发的事情.
相反,在调用函数之前,您需要一个调度机制来通过强制类型从泛型类型中重新实现特化f:
func f(v: MyStruct<String>) { print("String \(v)") }
func f(v: MyStruct<Int>) { print("Int \(v)") }
func f(v: MyType) {
switch v {
case let str as MyStruct<String>:
f(str)
case let num as MyStruct<Int>:
f(num)
default:
fatalError("unsupported type")
break
}
}
Run Code Online (Sandbox Code Playgroud)
默认情况是您的"保证"发挥作用的地方.switch就语言而言,没有办法详尽无遗,因此您需要进行运行时测试,以确保您没有尝试调用f比您声明定义的类型更多的类型.
所以,确实,你猜测需要一个switch是正确的.但这是一个好主意,因为它(或类似的东西)是消除泛型类型歧义的唯一方法.您至少可以将其限制为需要处理您的MyType协议Any.