Swift 满足ExpressibleByArrayLiteral协议
为什么在swift中扩展ExpressibleByArrayLiteral协议时,需要使用init。在协议的定义中,init方法只是公共的 我的内容与文档中的内容基本相同,但编译器仍抱怨将此Swift 满足ExpressibleByArrayLiteral协议,swift,protocols,Swift,Protocols,为什么在swift中扩展ExpressibleByArrayLiteral协议时,需要使用init。在协议的定义中,init方法只是公共的 我的内容与文档中的内容基本相同,但编译器仍抱怨将此init(arrayLiteral:Element…)设置为必需。我唯一的区别是我在一个类中实现它,而不是在一个结构中。有什么建议吗 更新: 下面是我的代码的一个实现: public class Stack<T> { private var buffer: [T] init() { se
init(arrayLiteral:Element…)
设置为必需。我唯一的区别是我在一个类中实现它,而不是在一个结构中。有什么建议吗
更新:
下面是我的代码的一个实现:
public class Stack<T> {
private var buffer: [T]
init() {
self.buffer = []
}
public func push(_ value: T) {
self.buffer.append(value)
}
public func pop() -> T? {
return self.buffer.popLast()
}
var size: Int {
return self.buffer.count
}
var isEmpty: Bool {
return self.size == 0
}
}
extension Stack: ExpressibleByArrayLiteral {
init(arrayLiteral: T...) {
for item in arrayLiteral {
self.push(item)
}
}
}
公共类堆栈{
专用变量缓冲区:[T]
init(){
self.buffer=[]
}
公共函数推送(u值:T){
self.buffer.append(值)
}
公共函数pop()->T{
返回self.buffer.popLast()
}
变量大小:Int{
返回self.buffer.count
}
var isEmpty:布尔{
返回self.size==0
}
}
扩展堆栈:ExpressibleByArrayLiteral{
初始(阵列并行:T…){
用于阵列中的项目并行{
自我推送(项目)
}
}
}
我得到的错误是:
1) 不能在“堆栈”的扩展中声明指定的初始值设定项;你是说这是一个方便的初始化器吗
2) 必须将初始值设定项“init(arrayLiteral:)”声明为公共,因为它符合公共协议“ExpressibleByArrayLiteral”中的要求
3) 初始值设定项要求“init(arrayLiteral:)”只能由非最终类“Stack”定义中的必需的初始值设定项来满足
问题:
对于错误#1->为什么我不能在扩展中声明指定的init
对于错误#2->我理解这一部分,协议将其定义为公共。但是为什么文档在实现它时没有使用public关键字呢
对于错误#3->这几乎是我最大的问题,为什么需要这样做
谢谢你的帮助 原因是继承:协议中的任何init
如果被类采用,则必须标记为required
。无法继承结构
对于一个类,init
必须初始化同一类的实例或返回nil
。当该类采用协议时,其自身及其所有子类必须提供自己的实现,以便编译器能够验证这一事实:
class ClassA : ExpressibleByArrayLiteral {
required init(arrayLiteral elements: Self.Element...) {
// this implicitly returns an instance of ClassA
}
}
class ClassB : ClassA {
// without its own init(arrayLitteral:), it will fallback on ClassA's init and return
// an instance of ClassA, which Swift does not allow.
}
这是由于斯威夫特的静态打字系统。与Objective-C不同,在Objective-C中,您认为自己创建了一个NSString
,但实际上得到了一个\nscontiguausstring
(所谓的设计模式)
只需去掉扩展并在类的定义中实现它:
public class Stack<T> : ExpressibleByArrayLiteral {
private var buffer: [T]
init() {
self.buffer = []
}
public func push(_ value: T) {
self.buffer.append(value)
}
public func pop() -> T? {
return self.buffer.popLast()
}
var size: Int {
return self.buffer.count
}
var isEmpty: Bool {
return self.size == 0
}
// MARK: -
required public init(arrayLiteral: T...) {
self.buffer = []
for item in arrayLiteral {
self.push(item)
}
}
}
公共类堆栈:ExpressibleByArrayLiteral{
专用变量缓冲区:[T]
init(){
self.buffer=[]
}
公共函数推送(u值:T){
self.buffer.append(值)
}
公共函数pop()->T{
返回self.buffer.popLast()
}
变量大小:Int{
返回self.buffer.count
}
var isEmpty:布尔{
返回self.size==0
}
//标记:-
必需的公共初始化(阵列并行:T…){
self.buffer=[]
用于阵列中的项目并行{
自我推送(项目)
}
}
}
对于错误#1->为什么我不能在扩展中声明指定的init
因为方便的初始值设定项必须调用指定的初始值设定项。扩展名可以在其他文件中定义。在当前结构中,该类可能没有在此编译单元(文件)中定义指定的初始值设定项,这会给当前编译器造成太多混乱。(这并不是说这是一个无法解决的类型理论问题;它只是在需要解决单个文件中的所有问题时产生了问题。)扩展名就是扩展名。如果它们从根本上改变了对象的工作方式(比如创建指定的初始值设定项),那么它们可能无法成为扩展
对于错误#2->我理解这一部分,协议将其定义为公共。但是为什么文档在实现它时没有使用public关键字呢
因为文档呈现程序总是在协议上剥离public
。如果这造成了混乱,请打开一个bug到bugs.swift.org
对于错误#3->这几乎是我最大的问题,为什么需要这样做
因为这是一门非期末课。考虑是否有一个子类,它使用了自己需要的初始化器。如何确保init(arrayLiteral:)
调用它?它无法调用它(因为它不知道它存在)。因此,init(arrayLiteral:)
必须是必需的
(这意味着它必须是主声明的一部分,而不是扩展),或者堆栈
必须是最终的
如果将其标记为final
,则其工作原理与预期相同。如果您想将其子类化,只需将其移出扩展并移入主体中,然后像这样定义它:
public convenience required init(arrayLiteral: T...) {
self.init()
for item in arrayLiteral {
self.push(item)
}
}
相关:。您需要使用
required
初始化器来实现初始化器需求,以确保可以调用所有潜在的子类。我猜:您有多个init,但编译器需要知道哪个是必需的。当您说“我几乎有相同的东西”时,不清楚您的意思是什么。您引用的代码不是“扩展ExpressibleByArrayLiteral协议”,而是扩展OrderedSet
以符合该协议,这是完全不同的。你为什么不发布有问题的代码以及你希望它做什么。(我很确定我知道你的问题是什么,但在猜测代码时很难讨论。)我将再次强调,因为required
是一个信号,初始化器必须对所有子类可用,结构和最终类不需要标记为required
,因为,由于不可能有子类,所以我
public convenience required init(arrayLiteral: T...) {
self.init()
for item in arrayLiteral {
self.push(item)
}
}