Swift枚举似乎非常适合在Swift3中建模字节操作码。例如:
enum MathOpCode:UInt8 {
case Add = 0
case Subtract = 1
case Multiply = 2
case Divide = 3
}
let a = 42
let b = 13
let someByte = 2
if let opcode = OpCode(rawValue: someByte) {
switch opcode {
case .Add:
return a + b
case .Subtract:
return a - b
case .Multiply:
return a * b
case .Divide:
return a / b
}
}
这对于编写二进制协议非常有用。枚举很好地捕获了逻辑操作码,然后开关读得很好。对我而言,OpCodes包含少量数据的地方。 IOW,我要说我添加了一个名为AddSmallConstant
的OpCode,它代表所有匹配0b01nnnnnn
的操作码,其中前两位必须是01
,但是底部的6位是嵌入常数0-63。我可以在我的枚举中添加64个案例......
enum MathOpCode:UInt8 {
...
case AddConstant0 = 0b01000000
case AddConstant1 = 0b01000001
...
case AddConstant63 = 0b01111111
}
这并不能很好地扩展。为了获得嵌入的值,我必须使用rawValue和masking操作来获取它。我不能有一个看起来像
的switch语句case MathOpCode.AddConstant0...MathOpCode.AddConstant63
匹配整个范围,因为枚举案例无法转换为范围。替代方案是在整个地方使用rawValue
:
switch opCode.rawValue {
case MathOpCode.Add.rawValue:
...
case MathOpCode.Subtract.rawValue:
...
case (MathOpCode.AddConstant0.rawValue)...(MathOpCode.AddConstant63.rawValue):
...
}
现在enum看起来像是行李,最好只定义一堆常量让我的文件顶部。我错过了一个更好的模式,我可以在Swift中使用它来表达这些类型的关系和模式吗?
答案 0 :(得分:1)
如您所知,Swift有一个名为关联值的奇特功能,但不幸的是,您无法控制具有关联值的枚举的原始位表示。
如果您想控制MathOpCode
类型的原始位代表,则可能需要创建RawRepresentable
类型。
例如,你可以这样写:
struct MathOpCode: RawRepresentable {
var rawValue: UInt8
init(rawValue: UInt8) {self.rawValue = rawValue}
static let add = MathOpCode(rawValue: 0)
static let subtract = MathOpCode(rawValue: 1)
static let multiply = MathOpCode(rawValue: 2)
static let divide = MathOpCode(rawValue: 3)
static let addConstant = MathOpCode(rawValue: 0b0100_0000)
static func add(constant value: UInt8) -> MathOpCode {
guard value < 64 else {fatalError("constant out of bounds")}
return MathOpCode(rawValue: self.addConstant.rawValue + value)
}
var isAddConstant: Bool {return self.rawValue & 0b1100_0000 == MathOpCode.addConstant.rawValue}
var constant: UInt8 {return self.rawValue & 0b0011_1111}
}
//Prepare `matches` operator for `switch`.
func ~= (lhs: MathOpCode, rhs: MathOpCode) -> Bool {
return lhs == MathOpCode.addConstant && rhs.isAddConstant
|| lhs == rhs
}
您可以将其用作:
let opCode = MathOpCode.add(constant: 22)
switch opCode {
case MathOpCode.add:
print("add")
case MathOpCode.subtract:
print("subtract")
case MathOpCode.multiply:
print("multiply")
case MathOpCode.divide:
print("divide")
case MathOpCode.addConstant:
print("addConstant", opCode.constant)
default:
print("invalid opCode")
}
//->addConstant 22