我在尝试遵守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"
我实施了ExtendedGraphemeClusterLiteralConvertible
和UnicodeScalarLiteralConvertible
协议(无论在地球上是什么意思)。
但是我仍然遇到错误,必须为ExtendedGraphemeClusterLiteralType
和UnicodeScalarLiteralType
提供定义:
typealias ExtendedGraphemeClusterLiteralType = String
typealias UnicodeScalarLiteralType = String
为什么我必须提供这个,如果它已经在标准标题???
中编译器认为它仍然有权投诉并强迫我将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)
}
}
斯威夫特,如果你喜欢编译器对你大吼大叫,你会爱上它! :-P
答案 0 :(得分:6)
第一个问题的答案在于,具有关联类型的Swift协议可以被认为是抽象的,并且需要绑定到特定类型。关联类型是使用更专业的方法(如类MyClass)的替代方法:IsCompatibleWith< Int> {}。我认为这样做的原因是具有共同的层次结构,但这种限制也会引起许多其他问题。无论如何,您需要指定协议绑定的类型,这是合理的。在Swift中,您可以通过类型别名关联类型到您想要的类型(在您的情况下为String)。
另请注意,协议中未指定关联类型,协议仅指定您必须定义它。也就是说,除非你的类上有相互冲突的方法,编译器通常可以推断出相关的类型(在某处的文档中阅读)。
默认情况下,协议中指定的初始化程序似乎是必需的。文档说您可以将它们实现为设计或方便,但这两种方式都是必需的:
协议初始化程序要求的类实现
您可以在符合标准上实现协议初始化程序要求 class作为指定的初始化程序或便捷初始化程序。 在这两种情况下,您都必须使用标记初始化程序实现 必需的修饰符:
class SomeClass: SomeProtocol { required init(someParameter: Int) { // initializer implementation goes here } }
使用必需的修饰符可确保您提供显式 或者继承所有的初始化程序要求的实现 符合类的子类,使它们也符合 协议
从我的阅读中,它回答what
但不回答why
。