在Swift中有不同的方法来访问字节缓冲区,最常见的可能是UnsafeBufferPointer<UInt8>
,而实际存储可以在NSData
,[UInt8]
,{{1或其他。
如果我正在编写库代码,我希望它尽可能通用并适应用户对字节缓冲区的选择,同时仍然尽可能方便地使用它。我目前的代码如下:
ContiguousArray<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
}
现在,我可以轻松地为protocol BufferType {
func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R
}
func stringFromUTF8BytesGeneric(bytes: BufferType) throws -> String {
return try bytes.withUnsafeBufferPointer { ptr in
if let s = String(bytes: ptr, encoding: NSUTF8StringEncoding) {
return s
} else {
throw Error.StringEncodingFailure
}
}
}
:
NSData
但是我找不到一种方法来为泛型类型实现这个协议,例如extension NSData: BufferType {
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)
}
}
:
[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 { }
协议,例如BufferType
但不是其他类型,例如[UInt8]
?
与第一点相比,允许任意数组真的有意义吗?我不这么认为,但也许我错过了什么?
对于我正在尝试做的事情(抽象不同的字节缓冲区类型),我有一个更好的解决方案吗?
答案 0 :(得分:1)
(好吧,我在输入这个问题的时候确实找到了一个有用的解决方案......所以为了不浪费我的努力,我会发布自己的答案。也许还有其他更好的解决方案。)
您可以制定“通用”[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
}
}
的每个方法添加泛型约束,否则它会完全按照我的意愿工作:
ByteBuffer