【问题标题】:How to initialize with literals for generic type?如何使用泛型类型的文字进行初始化?
【发布时间】:2020-04-28 12:31:40
【问题描述】:

protocols用字面量实现初始化。

示例:通过使用ExpressibleByStringLiteral,我们可以执行以下操作:

struct MyString: ExpressibleByStringLiteral {
    let value: String

    init(stringLiteral value: String) {
        self.value = value
    }
}

let str: MyString = "Hello World!" // It's the same as: `MyString(stringLiteral: "Hello World!")`
str.value // "Hello World!"

此外,通过使用ExpressibleByIntegerLiteral,我们可以执行以下操作:

struct MyInt: ExpressibleByIntegerLiteral {
    let value: Int

    init(integerLiteral value: Int) {
        self.value = value
    }
}

let int: MyInt = 101 // It's the same as: `MyInt(integerLiteral: 101)`
int.value // 101

我的问题是:

我们如何为具有泛型类型的结构应用相同的逻辑?考虑我有以下结构:

struct MyCustom<T> {
    let value: T
}

我想做的是:

let custom1: MyCustom = "Hello World!"
custom1.value // "Hello World!"
// OR (since its generic)
let custom2: MyCustom = 101
custom1.value // 101

在这种情况下要遵循什么适当的协议?

【问题讨论】:

    标签: swift initialization swift-protocols


    【解决方案1】:

    没有一种可以遵循的协议,但您可以基于T 的泛型类型为所有ExpressibleByXLiteral 协议创建条件一致性。

    extension MyCustom: ExpressibleByUnicodeScalarLiteral, ExpressibleByExtendedGraphemeClusterLiteral, ExpressibleByStringLiteral where T == String {
        init(unicodeScalarLiteral value: T) {
            self.value = value
        }
    
        init(extendedGraphemeClusterLiteral value: T) {
            self.value = value
        }
    
        init(stringLiteral value: T) {
            self.value = value
        }
    }
    
    extension MyCustom: ExpressibleByIntegerLiteral where T == Int {
        init(integerLiteral value: T) {
            self.value = value
        }
    }
    
    let myString: MyCustom<String> = "String"
    let myInt: MyCustom<Int> = 21
    

    【讨论】:

    • 谢谢。这是否意味着在这种情况下我必须手动遵守所有协议?
    • @AhmadF 是的。正如我在回答中所说,没有可以遵循的 1 个“ExpressibleByAllLiterals”协议,因此您需要对所有此类协议一一进行。
    【解决方案2】:

    这可以通过条件一致性实现:

    extension MyCustom: ExpressibleByStringLiteral, ExpressibleByUnicodeScalarLiteral, ExpressibleByExtendedGraphemeClusterLiteral where T: ExpressibleByStringLiteral {
        init(stringLiteral value: T.StringLiteralType) {
            self.value = T(stringLiteral: value)
        }
    
        init(unicodeScalarLiteral value: T.UnicodeScalarLiteralType) {
            self.value = T(unicodeScalarLiteral: value)
        }
    
        init(extendedGraphemeClusterLiteral value: T.ExtendedGraphemeClusterLiteralType) {
            self.value = T(extendedGraphemeClusterLiteral: value)
        }
    }
    
    extension MyCustom: ExpressibleByIntegerLiteral where T: ExpressibleByIntegerLiteral {
        init(integerLiteral value: T.IntegerLiteralType) {
            self.value = T(integerLiteral: value)
        }
    }
    

    你可以这样做:

    let custom1: MyCustom<String> = "Hello World!"
    custom1.value // "Hello World!"
    // OR (since its generic)
    let custom2: MyCustom<Int> = 101
    custom2.value // 101
    

    不过,对于 ExpressibleByStringLiteral,您需要明确声明并实现继承的一致性。

    此外,您需要告诉 Swift 您想要哪种泛型类型(MyCustom&lt;Int&gt;MyCustom&lt;String&gt;),因为可能还有其他类型符合例如ExpressibleByIntegerLiteral。例如MyCustom 类型本身:

    let custom3: MyCustom<MyCustom<Int>> = 101
    custom3.value // MyCustom<Int>(value: 101)
    

    【讨论】:

    • 谢谢。这是否意味着在这种情况下我必须手动遵守所有协议?
    • @AhmadF 无论您有一个通用结构还是多个具体结构,协议都是相同的。所以是的,您必须使您的通用结构符合您要使用的所有ExpressibleByXYZLiteral 协议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-06
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 2020-03-15
    • 2019-03-16
    • 1970-01-01
    相关资源
    最近更新 更多