Swift 泛型结构的集合

Swift 泛型结构的集合,swift,generics,collections,struct,Swift,Generics,Collections,Struct,我在Swift中遇到了一些泛型问题。我有一个通用结构: struct MyStruct<T> { ... } 您会注意到我没有为MyStruct指定t的类型。这是因为我想存储任何MyStruct,独立于类型T 好吧,你说,用Any表示T([MyKeyType:MyStruct])。是的,但是当我从字典中获取结构时,我想也想保留每个结构的T的原始类型信息,这样当调用一个采用MyStruct的函数时,它就会被正确的T类型调用 下面是一个例子: // Setup var myStruct

我在Swift中遇到了一些泛型问题。我有一个通用结构:

struct MyStruct<T> { ... }
您会注意到我没有为
MyStruct
指定
t
的类型。这是因为我想存储任何
MyStruct
,独立于类型T

好吧,你说,用
Any
表示
T
[MyKeyType:MyStruct]
)。是的,但是当我从字典中获取结构时,我想想保留每个结构的
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

但这根本不是一个好主意,因为
Any
,嗯…,是任何类型。

泛型类型在Swift中并不统一
MyStruct
MyStruct
是完全不同的类型,就像
Int
String
一样,无论它们看起来有多相似。这是类型保留泛型系统的属性之一(与Java中的类型擦除泛型系统相反)

不同类型的泛型系统可以用于不同的事情。当您开始专门化并以自己的方式编写更通用的代码时,类型保留泛型是最好的,即编写符合协议的特定类型,然后编写使用这些协议的泛型函数或类型,或者使用泛型创建可以包含其他类型值的包装类型,而不考虑这些类型是什么

另一方面,您需要从泛型类型返回到内部的专用类型,或者尝试创建相关泛型类型的泛化的用例可能不那么简单

您要查找的内容需要两个部分:

  • 一种声明
    MyStruct
    MyStruct
    具有公共类型祖先的方法,因此可以将所述类型声明为字典中的元素类型
  • 从字典中取出后,根据
    MyStruct
    的特殊类型进行分派的一种方法
  • 第一部分 不要泛化类型参数,泛化整个类型:也就是说,不要为
    [MyKeyType:MyStruct]
    创建字典,为
    [MyKeyType:MyValueType]
    创建字典,其中
    MyValueType
    MyStruct
    MyStruct
    都遵守的协议。(你可以使用
    Any
    作为你的值类型,但是你的字典里会有一些东西不是
    MyStruct
    s)例如:

    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]
    
    默认情况下,您的“担保”起作用。就语言而言,无法使此
    开关
    详尽无遗,因此您需要进行运行时测试,以确保您没有尝试调用超出您所定义类型的
    f


    因此,事实上,您对需要
    开关的猜测是正确的。但这是一个好主意,因为它(或类似的东西)是消除泛型类型歧义的唯一方法。您至少可以将其限制为需要处理您的
    MyType
    协议,而不是
    Any

    unsafeTypeCast
    是。。。嗯,不安全,所以我建议不要使用它作为构建类型层次结构的基础,你可以对此进行推理。@rickster AFAIK,
    unsafeTypeCast
    是不安全的,因为你可能会执行
    unsafeTypeCast(myProbablyAnInt,Int.self)
    ,如果结果是
    myProbablyAnInt
    是一个
    字符串
    ,那么,然后程序崩溃了。我在这里以一种非不安全的方式使用它(我认为),只是为了避开自定义类型使用Swift的事实:我不能在需要使用
    MyStruct
    的地方给出
    MyStruct
    。感谢您的详细解释和有趣的建议。我将在我的代码中试用它们,看看它们是否符合我的要求。
    switch s1 {
    case let v as MyStruct<String>: f(v)
    ...
    }
    
    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]
    
    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
        }
    }