Swift 如何对不同的字节缓冲区类型进行抽象?(NSData[UInt8],&x2026;)

Swift 如何对不同的字节缓冲区类型进行抽象?(NSData[UInt8],&x2026;),swift,Swift,在Swift中访问字节缓冲区的方法有多种,最常用的方法可能是通过UnsafeBufferPointer,而实际的存储可以在NSData、[UInt8]、连续数组或其他地方 如果我在编写库代码,我希望它尽可能通用,并适应用户对字节缓冲区的选择,同时尽可能方便地使用。我当前的代码如下所示: import Foundation func stringFromUTF8Bytes(bytes: UnsafeBufferPointer<UInt8>) throws -> String {

在Swift中访问字节缓冲区的方法有多种,最常用的方法可能是通过
UnsafeBufferPointer
,而实际的存储可以在
NSData
[UInt8]
连续数组
或其他地方

如果我在编写库代码,我希望它尽可能通用,并适应用户对字节缓冲区的选择,同时尽可能方便地使用。我当前的代码如下所示:

import Foundation

func stringFromUTF8Bytes(bytes: UnsafeBufferPointer<UInt8>) throws -> String {
    if let s = String(bytes: bytes, encoding: NSUTF8StringEncoding) {
        return s
    } else {
        throw Error.StringEncodingFailure
    }
}

func stringFromUTF8Bytes(bytes: ContiguousArray<UInt8>) throws -> String {
    return try bytes.withUnsafeBufferPointer(stringFromUTF8Bytes)
}

func stringFromUTF8Bytes(bytes: [UInt8]) throws -> String {
    return try bytes.withUnsafeBufferPointer(stringFromUTF8Bytes)
}

func stringFromUTF8Bytes(data: NSData) throws -> String {
    return try data.withUnsafeBufferPointer(stringFromUTF8Bytes)
}

enum Error: ErrorType {
    case StringEncodingFailure
}
但是我找不到一种方法来为泛型类型实现此协议,例如为
[UInt8]

// error: constrained extension must be declared on the unspecialized generic type 'Array' with constraints specified by a 'where' clause
extension Array<UInt8>: BufferType { }

// error: same-type requirement makes generic parameter 'Element' non-generic
extension Array: BufferType where Element == UInt8 { }
//错误:必须在非专用泛型类型“Array”上声明受约束的扩展,并使用“where”子句指定的约束
扩展数组:缓冲类型{}
//错误:相同类型要求使泛型参数“Element”非泛型
扩展数组:BufferType,其中元素==UInt8{}
我的问题是:

  • 是否有一种方法可以为例如
    [UInt8]
    而不是像
    [NSWindowController]
    这样的其他类型实现
    缓冲类型
    协议

  • 与第一点不同的是,允许任意数组真的有意义吗?我不这么认为,但也许我错过了什么

  • 有没有更好的解决方案来解决我完全没有解决的问题(对不同的字节缓冲区类型进行抽象)

(好吧,我自己在打这个问题时找到了一个有效的解决方案……所以为了不浪费精力,我将发布我自己的答案。也许还有其他更好的解决方案。)

您可以创建一个“通用的”
BufferType
协议,并约束协议的实际使用,而不是协议的实现。这类似于标准库中使用的
SequenceType

protocol BufferType {
    typealias Element
    func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R
}

extension NSData: BufferType {
    typealias Element = UInt8
    func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R {
        let bytesBufferPointer = UnsafeBufferPointer<UInt8>(start: UnsafePointer<UInt8>(bytes), count: length)
        return try body(bytesBufferPointer)
    }
}

extension UnsafeBufferPointer: BufferType {
    func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R {
        return try body(self)
    }
}

extension Array: BufferType { }
extension ContiguousArray: BufferType { }

func stringFromUTF8BytesGeneric <BT: BufferType where BT.Element == UInt8> (bytes: BT) throws -> String {
    switch(bytes.withUnsafeBufferPointer { String(bytes: $0, encoding: NSUTF8StringEncoding) }) {
    case let .Some(str): return str
    case .None: throw Error.StringEncodingFailure
    }
}
// error: constrained extension must be declared on the unspecialized generic type 'Array' with constraints specified by a 'where' clause
extension Array<UInt8>: BufferType { }

// error: same-type requirement makes generic parameter 'Element' non-generic
extension Array: BufferType where Element == UInt8 { }
protocol BufferType {
    typealias Element
    func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R
}

extension NSData: BufferType {
    typealias Element = UInt8
    func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R {
        let bytesBufferPointer = UnsafeBufferPointer<UInt8>(start: UnsafePointer<UInt8>(bytes), count: length)
        return try body(bytesBufferPointer)
    }
}

extension UnsafeBufferPointer: BufferType {
    func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R {
        return try body(self)
    }
}

extension Array: BufferType { }
extension ContiguousArray: BufferType { }

func stringFromUTF8BytesGeneric <BT: BufferType where BT.Element == UInt8> (bytes: BT) throws -> String {
    switch(bytes.withUnsafeBufferPointer { String(bytes: $0, encoding: NSUTF8StringEncoding) }) {
    case let .Some(str): return str
    case .None: throw Error.StringEncodingFailure
    }
}
// both print "ABC"
print(try stringFromUTF8BytesGeneric([65, 66, 67]))
print(try stringFromUTF8BytesGeneric(ContiguousArray<UInt8>([65, 66, 67])))