满足 ExpressibleByArrayLiteral 协议 [英] Satisfying ExpressibleByArrayLiteral Protocol

查看:47
本文介绍了满足 ExpressibleByArrayLiteral 协议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么当我在 swift 中扩展 ExpressibleByArrayLiteral 协议时,我需要使 init 成为必需.在协议的定义中,init 方法只是公开的.

Why when I extend the ExpressibleByArrayLiteral protocol in swift I need to make the init required. In the definition of the protocol, the init method is just public.

我与文档中的内容几乎相同,https://developer.apple.com/reference/swift/expressiblebyarrayliteral,而且编译器仍然抱怨需要这个 init(arrayLiteral: Element...).我唯一的区别是我在一个没有结构的类中实现它.有什么建议吗?

I pretty much have the same thing as in the doc, https://developer.apple.com/reference/swift/expressiblebyarrayliteral, and still, the compiler complains about making this init(arrayLiteral: Element...) required. The only difference I have is that I am implementing it in a class no a struct. Any suggestions?

更新:

这是我的代码的实现:

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)
        }
    }
}

我得到的错误是:

1) 不能在'Stack'的扩展中声明指定的初始化器;你的意思是这是一个方便的初始化程序吗?

1) designated initializer cannot be declared in an extension of 'Stack'; did you mean this to be a convenience initializer?

2) 初始化器 'init(arrayLiteral:)' 必须声明为 public,因为它符合公共协议 'ExpressibleByArrayLiteral' 中的要求

2) initializer 'init(arrayLiteral:)' must be declared public because it matches a requirement in public protocol 'ExpressibleByArrayLiteral'

3) 初始化器要求 'init(arrayLiteral:)' 只能由非最终类 'Stack' 定义中的 required 初始化器来满足

3) initializer requirement 'init(arrayLiteral:)' can only be satisfied by a required initializer in the definition of non-final class 'Stack'

问题:

对于错误 #1 -> 为什么我不能在扩展中声明指定的 init?

For error #1 -> Why can't I declare a designated init in an extension?

对于错误 #2 -> 我理解这部分,协议将其定义为公开.但是为什么文档在没有 public 关键字的情况下实现它?

For error #2 -> I understand this part, the protocol defines this as public. But why does the docs implement it with out the public keyword?

对于错误 #3 -> 这几乎是我最大的问题,为什么需要这样做.

For error #3 -> This is pretty much my biggest question, why this needs to be required.

感谢您的帮助!

推荐答案

原因是继承:协议内的任何 init 必须标记为 required 如果被一个协议采用班级.struct 不能被继承.

The reason is inheritance: any init inside a protocol must be marked as required if adopted by a class. A struct cannot be inherited.

对于一个类,init 必须初始化同一个类的实例或返回 nil.当该类采用协议时,其自身及其所有子类必须提供自己的实现,以便编译器可以验证这一事实:

For a class, An init must initialize an instance of that same class or return nil. When that class adopts a protocol, itself and all its subclasses must provide their own implementations so the compiler can verify that fact:

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.
}

这是由于 Swift 的静态类型系统.不像在 Objective-C 中,你认为你创建了一个 NSString 但实际上得到了一个 _NSContiguousString(所谓的 类簇设计模式)

This is due to Swift's static typing system. Unlike in Objective-C where you think you create an NSString but actually get an _NSContiguousString instead (the so-called class cluster design pattern)

NSString * str = [[NSString alloc] initWithString:@"Hello world"];
// surprise: you may get an _NSContiguousString instead

<小时>

去掉扩展并在类的定义中实现它:


Just get rid of the extension and implement it in the class's definition:

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 协议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆