我试图编写一个帮助函数,它将一个位索引数组转换为一个符合OptionSet的类。
func getOptionSet<T: OptionSet>(bitIndexes: [Int64]) -> T {
var result: Int64 = 0
for index in bitIndexes {
result |= 1 << index
}
return T(rawValue: result) // error
}
无法编译:
Cannot invoke initializer for type 'T' with an argument list of type '(rawValue: Int64)'
我也尝试过使用RawValue:
func getOptionSet<T: OptionSet>(bitIndexes: [T.RawValue]) {
var result = T.RawValue() // error
这也不起作用:
Cannot invoke value of type 'T.RawValue.Type' with argument list '()'
可以这样做吗?我是否需要在T上添加其他约束?
我知道可以重写此函数以使用具体类型,但我希望尽可能保持通用。
答案 0 :(得分:4)
代码中的问题是Int64
和T.RawValue
不相关的,可以是不同的类型。
但是每个无符号整数类型都可以从和转换
到UIntMax
,因此可以通过将RawValue
限制为UnsignedInteger
来解决问题。
使用@ OOPer的想法来定义自定义初始化程序,这将是:
extension OptionSet where RawValue: UnsignedInteger {
init(bitIndexes: [Int]) {
var result: UIntMax = 0
for index in bitIndexes {
result |= 1 << UIntMax(index)
}
self.init(rawValue: RawValue(result))
}
}
也可以写成
extension OptionSet where RawValue: UnsignedInteger {
init(bitIndexes: [Int]) {
let result = bitIndexes.reduce(UIntMax(0)) {
$0 | 1 << UIntMax($1)
}
self.init(rawValue: RawValue(result))
}
}
到目前为止,我看到的所有选项集类型都有一个无符号整数
键入原始值,但请注意,同样也可以使用
SignedInteger
和IntMax
。
示例:
struct TestSet: OptionSet {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
}
let ts = TestSet(bitIndexes: [1, 4])
print(ts) // TestSet(rawValue: 18)
还要比较How do you enumerate OptionSetType in Swift?的反向任务。
更新:从 Swift 4 开始,UnsignedInteger
协议有
public static func << <RHS>(lhs: Self, rhs: RHS) -> Self where RHS : BinaryInteger
方法,以便上面的代码可以简化为
extension OptionSet where RawValue: UnsignedInteger {
init(bitIndexes: [Int]) {
self.init(rawValue: bitIndexes.reduce(0) { $0 | 1 << $1 })
}
}
没有中间转换为“最大”整数类型。
答案 1 :(得分:3)
您可能需要更多设置才能使getOptionSet
正常工作:
protocol OptionBitShiftable: IntegerLiteralConvertible {
func << (lhs: Self, rhs: Self) -> Self
func |= (lhs: inout Self, rhs: Self)
}
extension Int64: OptionBitShiftable {}
extension UInt64: OptionBitShiftable {}
//...
有了上述内容,您可以像这样写getOptionSet
:
func getOptionSet<T: OptionSet where T.RawValue: OptionBitShiftable>(bitIndexes: [T.RawValue]) -> T {
var result: T.RawValue = 0
for index in bitIndexes {
result |= 1 << index
}
return T(rawValue: result)
}
用法:
struct MyOptionSet: OptionSet {
var rawValue: Int64
init(rawValue: Int64) {
self.rawValue = rawValue
}
}
let myOption: MyOptionSet = getOptionSet(bitIndexes: [1,2,3,5,7])
print(myOption.rawValue) //->174(=2+4+8+32+128)
或者,您可以像这样定义一个初始值设定项:
extension OptionSet where RawValue: OptionBitShiftable {
init(bitIndexes: [RawValue]) {
var result: RawValue = 0
for index in bitIndexes {
result |= 1 << index
}
self.init(rawValue: result)
}
}
您可以将其用作:
let alsoMyOption = MyOptionSet(bitIndexes: [4, 6])
print(alsoMyOption.rawValue) //->80(=16+64)