Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 满足ExpressibleByArrayLiteral协议_Swift_Protocols - Fatal编程技术网

Swift 满足ExpressibleByArrayLiteral协议

Swift 满足ExpressibleByArrayLiteral协议,swift,protocols,Swift,Protocols,为什么在swift中扩展ExpressibleByArrayLiteral协议时,需要使用init。在协议的定义中,init方法只是公共的 我的内容与文档中的内容基本相同,但编译器仍抱怨将此init(arrayLiteral:Element…)设置为必需。我唯一的区别是我在一个类中实现它,而不是在一个结构中。有什么建议吗 更新: 下面是我的代码的一个实现: public class Stack<T> { private var buffer: [T] init() { se

为什么在swift中扩展ExpressibleByArrayLiteral协议时,需要使用init。在协议的定义中,init方法只是公共的

我的内容与文档中的内容基本相同,但编译器仍抱怨将此
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)
    }
}