首页 > 解决方案 > Swift:非泛型结构中的泛型初始化

问题描述

好的,我将尝试用一个最小的可行示例向您解释我想要得到什么:我想要一个这样的结构:

struct MyStruct {
    let aBool: Bool
    let aInt: Int
    let aHashable: Hashable?
}

但当然不能这样做,因为:

协议 'Hashable' 只能用作通用约束,因为它具有 Self 或关联的类型要求

这很好。我可以通过这种方式得到我想要的:

struct MyStruct<T> where T: Hashable {
    let aBool: Bool
    let aInt: Int
    let aHashable: T?
}

但我希望我的结构以这种方式有两个初始化:

struct MyStruct<T> where T: Hashable {
    let aBool: Bool
    let aInt: Int
    let aHashable: T?

    init(aBool: Bool, aInt: Int) {
        self.init(aBool: aBool, aInt: aInt, aHashable: nil)
    }

    init(aHashable: T?) {
        self.init(aBool: false, aInt: 0, aHashable: aHashable)
    }

    private init(aBool: Bool, aInt: Int, aHashable: T?) {
        self.aBool = aBool
        self.aInt = aInt
        self.aHashable = aHashable
    }
}

如果我尝试像这样初始化结构:

let myStruct = MyStruct(aBool: true, aInt: 10)

我收到一个错误:

无法推断通用参数“T”

问题是,即使我将结构转换为非通用结构(带有几个通用 init):

struct MyStruct {
    let aBool: Bool
    let aInt: Int
    let aHashable: T?

    init(aBool: Bool, aInt: Int) {
        self.init(aBool: aBool, aInt: aInt, aHashable: nil)
    }

    init<T>(aHashable: T?) where T: Hashable {
        self.init(aBool: false, aInt: 0, aHashable: aHashable)
    }

    private init<T>(aBool: Bool, aInt: Int, aHashable: T?) where T: Hashable {
        self.aBool = aBool
        self.aInt = aInt
        self.aHashable = aHashable
    }
}

我仍然收到错误消息。这次在let aHashable: T?存储的属性上:

使用未声明的类型“T”

得到我想要的东西的正确方法是什么?谢谢你。

标签: iosswiftgenerics

解决方案


在这种T情况下,您想要的是Never,因为它永远不会有值。要定义这种初始化,您需要将其限制在这样的扩展中:

extension MyStruct where T == Never {
    init(aBool: Bool, aInt: Int) {
        self.init(aBool: aBool, aInt: aInt, aHashable: nil)
    }
}

IMO,Swift 也应该允许这样做:

init(aBool: Bool, aInt: Int) where T == Never {...}

但这不是目前合法的 Swift。你必须把它放在一个扩展中。这只是一个语法问题。

为了完整起见,这里是完整的代码:

struct MyStruct<T> where T: Hashable {
    let aBool: Bool
    let aInt: Int
    let aHashable: T?

    init(aHashable: T?) {
        self.init(aBool: false, aInt: 0, aHashable: aHashable)
    }

    private init(aBool: Bool, aInt: Int, aHashable: T?) {
        self.aBool = aBool
        self.aInt = aInt
        self.aHashable = aHashable
    }
}

extension MyStruct where T == Never {
    init(aBool: Bool, aInt: Int) {
        self.init(aBool: aBool, aInt: aInt, aHashable: nil)
    }
}

let myStruct = MyStruct(aBool: true, aInt: 10)

推荐阅读