将位索引数组转换为 OptionSet

Zme*_*mey 2 generics bitvector bit-fields swift swift3

我正在尝试编写一个辅助函数,它将把位索引数组转换为符合 OptionSet 的类。

func getOptionSet<T: OptionSet>(bitIndexes: [Int64]) -> T {
    var result: Int64 = 0
    for index in bitIndexes {
        result |= 1 << index
    }
    return T(rawValue: result) // error
}
Run Code Online (Sandbox Code Playgroud)

这无法编译:

Cannot invoke initializer for type 'T' with an argument list of type '(rawValue: Int64)'
Run Code Online (Sandbox Code Playgroud)

我也尝试过使用 RawValue:

func getOptionSet<T: OptionSet>(bitIndexes: [T.RawValue]) {
    var result = T.RawValue()  // error
Run Code Online (Sandbox Code Playgroud)

这也不起作用:

Cannot invoke value of type 'T.RawValue.Type' with argument list '()'
Run Code Online (Sandbox Code Playgroud)

这可以做到吗?我需要对 T 添加额外的约束吗?

我知道可以重写这个函数以使用具体类型,但如果可能的话我想保持它的通用性。

Mar*_*n R 5

你的代码中的问题是Int64和T.RawValue不相关并且可以是不同的类型。

\n\n

但是每个无符号整数类型都可以从 and\n 转换为,因此可以通过限制为来UIntMax解决问题RawValueUnsignedInteger。

\n\n

使用 @OOPer\ 的想法来定义自定义初始值设定项,这将是:

\n\n
extension OptionSet where RawValue: UnsignedInteger {\n    init(bitIndexes: [Int]) {\n        var result: UIntMax = 0\n        for index in bitIndexes {\n            result |= 1 << UIntMax(index)\n        }\n        self.init(rawValue: RawValue(result))\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

也可以写成

\n\n
extension OptionSet where RawValue: UnsignedInteger {\n    init(bitIndexes: [Int]) {\n        let result = bitIndexes.reduce(UIntMax(0)) {\n            $0 | 1 << UIntMax($1)\n        }\n        self.init(rawValue: RawValue(result))\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

到目前为止我看到的所有选项集类型都有一个无符号整数\n类型作为原始值,但请注意,同样也适用于\nSignedInteger和IntMax。

\n\n

例子:

\n\n
struct TestSet: OptionSet {\n    let rawValue: UInt16\n    init(rawValue: UInt16) {\n        self.rawValue = rawValue\n    }\n}\n\nlet ts = TestSet(bitIndexes: [1, 4])\nprint(ts) // TestSet(rawValue: 18)\n
Run Code Online (Sandbox Code Playgroud)\n\n

另请比较如何在 Swift 中枚举 OptionSetType?用于反向任务。

\n\n
\n\n

更新:从Swift 4 开始UnsignedInteger协议有一个

\n\n
public static func << <RHS>(lhs: Self, rhs: RHS) -> Self where RHS : BinaryInteger\n
Run Code Online (Sandbox Code Playgroud)\n\n

方法,这样上面的代码就可以简化为

\n\n
extension OptionSet where RawValue: UnsignedInteger {\n    init(bitIndexes: [Int]) {\n        self.init(rawValue: bitIndexes.reduce(0) { $0 | 1 << $1 })\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

无需中间转换为 \xe2\x80\x9cmaximal\xe2\x80\x9d 整数类型。

\n