条件协议一致性:无法将类型 'Array<_>' 的值转换为指定类型“[UInt8]”

Conditional Protocol Conformance: Cannot convert value of type 'Array<_>' to specified type '[UInt8]'

尝试使用条件一致性扩展 Swift 4.1 中的数组、字符串和字典,但在尝试使用 Element 初始化数组时 运行 陷入死胡同通过名为 BinaryCodable.

的自定义协议符合 Decodable/Encodable

以下摘录来自 https://github.com/mikeash/BinaryCoder,但已进行调整以使用 Swift 的新条件一致性以使其能够编译。

extension Array: BinaryCodable where Element: BinaryDecodable, Element: BinaryEncodable {
    public func binaryEncode(to encoder: BinaryEncoder) throws {
        try encoder.encode(self.count)
        for element in self {
            try element.encode(to: encoder)
        }
    }

    public init(fromBinary decoder: BinaryDecoder) throws {
        let binaryElement = Element.self

        let count = try decoder.decode(Int.self)
        self.init()
        self.reserveCapacity(count)
        for _ in 0 ..< count {
            let decoded = try binaryElement.init(from: decoder)
            self.append(decoded)
        }
    }
}

extension String: BinaryCodable {
    public func binaryEncode(to encoder: BinaryEncoder) throws {
        try (Array(self.utf8) as! BinaryCodable).binaryEncode(to: encoder)
    }

    public init(fromBinary decoder: BinaryDecoder) throws {
        let utf8: [UInt8] = try Array(fromBinary: decoder)
        if let str = String(bytes: utf8, encoding: .utf8) {
            self = str
        } else {
            throw BinaryDecoder.Error.invalidUTF8(utf8)
        }
    }
}

但是,我得到:

Cannot convert value of type 'Array<_>' to specified type '[UInt8]'

对于这一行:

let utf8: [UInt8] = try Array(fromBinary: decoder)

如有任何帮助,我们将不胜感激。

如果您希望数组的每个元素都有一个值,请将其更改为:

let utf8:Array<UInt8> = try Array(from: decoder);

如果您希望数组的某些元素具有 null 或空值,请将其更改为:

let utf8:Array<UInt8?> = try Array(from: decoder);

为了使 Array<UInt8> 成为 BinaryCodable,它的元素类型 UInt8 必须是 BinaryCodable,但事实并非如此。该协议有 其所需方法的默认实现,但一致性必须 仍然明确声明:

extension UInt8: BinaryCodable {}

然后你的extension String编译, 你甚至可以去掉强制转换 as! BinaryCodable 编码方式(使用guard可以节省一行):

extension String: BinaryCodable {
    public func binaryEncode(to encoder: BinaryEncoder) throws {
        try Array(self.utf8).binaryEncode(to: encoder)
    }

    public init(fromBinary decoder: BinaryDecoder) throws {
        let utf8: [UInt8] = try Array(fromBinary: decoder)
        guard let str = String(bytes: utf8, encoding: .utf8) else {
            throw BinaryDecoder.Error.invalidUTF8(utf8)
        }
        self = str
    }
}