试图符合StringLiteralConvertible

cfi*_*her 11 protocols swift

在尝试符合StringLiteralConvertible时,我遇到了一些奇怪的事情:

class Person: StringLiteralConvertible {
    var name = ""

    init(name n:String){
        name = n
    }

    init(stringLiteral value: StringLiteralType){
        name = n
    }

    init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType){
        name = n
    }

    init(unicodeScalarLiteral value: UnicodeScalarLiteralType){
        name = n
    }
}




var ironMan = Person(name: "Tony Stark")
var spiderMan: Person = "Peter Parker"
Run Code Online (Sandbox Code Playgroud)

我实现了ExtendedGraphemeClusterLiteralConvertibleUnicodeScalarLiteralConvertible协议(无论在地球上意味着什么).

不过,我仍然有错误,必须提供两个定义ExtendedGraphemeClusterLiteralTypeUnicodeScalarLiteralType:

typealias ExtendedGraphemeClusterLiteralType = String
typealias UnicodeScalarLiteralType = String
Run Code Online (Sandbox Code Playgroud)

如果它已经在标准标题中,为什么我必须提供它?

编译器认为它仍然有权投诉并强迫我将required关键字添加到inits中,即使协议的定义不包含required关键字!为什么????

下面的代码编译,但我不明白为什么第一个版本没有编译!

class Person: StringLiteralConvertible {
    var name = ""

    init(name n:String){
        name = n
    }

    typealias ExtendedGraphemeClusterLiteralType = String
    typealias UnicodeScalarLiteralType = String

    required convenience init(stringLiteral value: StringLiteralType){
        self.init(name: value)
    }

    required convenience init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType){
        self.init(name: value)
    }

    required convenience init(unicodeScalarLiteral value: UnicodeScalarLiteralType){
        self.init(name: value)
    }
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特,如果你喜欢编译器对你大吼大叫,你会爱上它!:-P

Chr*_*ver 6

为什么选择typealases:

第一个问题的答案在于,具有关联类型的Swift协议可以被认为是抽象的,并且需要绑定到特定类型.关联类型是使用类MyClass等更专业方法的替代方法:IsCompatibleWith <Int> {}.我认为这样做的原因是具有共同的层次结构,但这种限制也会引起许多其他问题.无论如何,您需要指定协议绑定的类型,这是合理的.在Swift中,您可以通过类型别名关联类型到您想要的类型(在您的情况下为String).

另请注意,协议中未指定关联类型,协议仅指定您必须定义它.也就是说,除非您的类上有相互冲突的方法,编译器通常可以推断出相关的类型(在某处的文档中阅读).

必需的初始化程序

看来协议中指定的初始化程序是默认/自然的.文档说您可以将它们实现为设计或方便,但这两种方式都是必需的:

协议初始化程序要求的类实现

您可以将符合类的协议初始值设定项要求实现为指定的初始值设定项或便捷初始值设定项.在这两种情况下,您必须使用required修饰符标记初始化程序实现:

class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
Run Code Online (Sandbox Code Playgroud)

使用必需的修饰符可确保您在符合类的所有子类上提供初始化程序要求的显式或继承实现,以便它们也符合协议.

从我的阅读中,它回答what但不是why.