我想写一个帮助函数,它将位索引数组转换为符合OptionSet的类。将位索引数组转换为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上增加额外的约束条件?
我知道有可能重写这个函数来使用具体的类型,但是我想尽可能保持它的通用性。
谢谢,这非常有用。是否值得将所有内容转换为32位平台的UIntMax还是不是问题?让结果:UIntMax = bitIndexes.reduce(UIntMax(0)){UIntMax($ 0)| UIntMax(1)<< UIntMax($ 1)} – Zmey
@Zmey:即使在32位平台上,OptionSet类型也可以具有64位的RawValue。如果中间值仅为32位,则会丢失位。但你不需要'UIntMax($ 0)'或'UIntMax(1)',这些类型是自动推断的。 - 其实我从中可以看出编辑历史中的错误。现在应该是正确的。 –
@Zmey:中间结果/累加器也可以具有RawValue类型。问题是左移运算符<< <<没有在(Un)SignedInteger协议中定义,所以你必须为所有可能的原始类型定义额外的协议扩展,我试图避免这种扩展。 - 在这个答案的修订1中,我通过乘法而不是左移解决了这个问题。所以这是可能的,但我发现这个代码更优雅。 –