Swift代表整数类型的BinaryInteger协议
Swift代表整数类型的BinaryInteger协议

Swift代表整数类型的BinaryInteger协议

在 Swift 中,BinaryInteger 是一个协议,代表了所有二进制整数类型的通用特性和功能。它是整数类型的一个高级抽象,可以被 Swift 的标准整数类型(如 Int, UInt, Int8, UInt8 等)遵循,同时允许自定义的整数类型实现该协议。

1、协议定义

BinaryInteger 是继承自 NumericHashable 的协议,因此它具有数值操作和哈希功能。

2、应用范围

Swift 中所有的整数类型(有符号和无符号)都遵循 BinaryInteger。

可以扩展 BinaryInteger 来为所有整数类型提供通用功能。

3、功能特点

提供了整数类型的基本运算符支持(+, -, *, /, % 等)。

支持位操作(<<, >>, &, |, ~ 等)。

提供与不同类型的转换方法。

支持字节表示和整数的多进制操作。

常用方法和属性

BinaryInteger 协议提供了一些常用的功能和属性:

类型转换

1、init<T>(exactly source: T):从另一个数字类型进行精确初始化,如果不能表示则返回 nil。

检查目标类型是否可以精确表示 source。

如果值超出目标类型的范围(比如试图将一个 Int64 转换为 Int8 而数值超出了 Int8 的表示范围),则返回 nil。

let value = Int8(exactly: 300) // 返回 nil,因为 300 超出 Int8 范围
let value2 = Int8(exactly: 127) // 返回 127,因为在范围内

2、init<T>(_ source: T):从其他数字类型初始化,可能会截断。

将源类型的值转换为目标类型。如果超出范围,会保留低位部分(截断高位)。

let truncated = Int8(300) // 300 的二进制低位部分是 44,因此返回 44

3、magnitude:返回无符号值的绝对值。

如果值是负数,返回 -self 的无符号值;如果是正数,直接返回。

let x: Int = -5
print(x.magnitude) // 输出 5

位操作

1、leadingZeroBitCount:返回前导零的位数。

检查整数的二进制表示,从高位到低位统计连续零的数量,直到第一个非零位。

通常依赖硬件指令或库函数来计算。

let x: UInt8 = 0b00001111
print(x.leadingZeroBitCount) // 输出 4

2、trailingZeroBitCount:返回尾随零的位数。

检查整数的二进制表示,从低位到高位统计连续零的数量,直到第一个非零位。

let x: UInt8 = 0b00010000
print(x.trailingZeroBitCount) // 输出 4

3、bitWidth:整数类型的位宽。

对于固定宽度的类型,如 Int8、Int16 等,直接返回其位宽(例如 Int8.bitWidth = 8)。

对于其他自定义整数类型,可能需要动态计算。

let x: Int8 = 127
print(x.bitWidth) // 输出 8

4、nonzeroBitCount:非零位的数量。

遍历整数的二进制表示,统计所有 1 的个数。

常见实现是基于硬件加速的“汉明重量”算法。

let x: UInt8 = 0b11010010
print(x.nonzeroBitCount) // 输出 4

数值属性

1、isMultiple(of:):判断是否是某个数的倍数。

检查 self % other == 0。

let x = 12
print(x.isMultiple(of: 3)) // 输出 true
print(x.isMultiple(of: 5)) // 输出 false

2、signum():返回整数的符号(-1、0 或 1)。

实现逻辑

如果 self > 0,返回 1;

如果 self == 0,返回 0;

如果 self < 0,返回 -1。

let x = -42
print(x.signum()) // 输出 -1
let y = 0
print(y.signum()) // 输出 0
let z = 7
print(z.signum()) // 输出 1

运算符支持

1、标准算术运算符:+, -, *, /, %。

2、位运算符:&, |, ^, ~, <<, >>。

<< 和 >>:左移和右移,通常是基于硬件指令。

let x: UInt8 = 0b1100
print(x << 2) // 输出 0b110000

3、比较运算符:<, <=, >, >=.

示例代码

func isEven<T: BinaryInteger>(_ number: T) -> Bool {
    return number.isMultiple(of: 2)
}

let intNumber: Int = 4
let uintNumber: UInt = 7
let int8Number: Int8 = -6

print(isEven(intNumber))    // true
print(isEven(uintNumber))   // false
print(isEven(int8Number))   // true

应用示例

位操作示例

let value: Int = 12 // 二进制: 1100
print(value.leadingZeroBitCount) // 比如,在 64 位系统中输出 60
print(value.trailingZeroBitCount) // 输出 2,因为最低两位是 0
print(value.nonzeroBitCount) // 输出 2,因为有两个 1

自定义类型遵循 BinaryInteger

可以创建一个自定义类型,并让它遵循 BinaryInteger,从而使其具备整数类型的行为:

struct MyInt: BinaryInteger {
    private var value: Int

    // 必须实现的属性和方法
    var magnitude: UInt { return UInt(abs(value)) }
    init<T>(_ source: T) where T: BinaryInteger {
        self.value = Int(source)
    }
    init<T>(exactly source: T) where T: BinaryInteger? {
        guard let value = source.flatMap({ Int(exactly: $0) }) else {
            return nil
        }
        self.value = value
    }
    // 其余实现省略...
}

值得注意的是,在 Swift 中,实现复杂的协议(例如 BinaryInteger)需要实现许多协议要求。BinaryInteger 继承了多个协议,包括 AdditiveArithmetic、Numeric 和 ExpressibleByIntegerLiteral 等,每个协议都有具体的要求。

因此,不推荐自定义类型遵循BinaryInteger协议。

总结

BinaryInteger 是 Swift 提供的一个协议,用于描述和抽象整数类型的通用行为。它使得所有整数类型共享一套功能,并且可以通过泛型和扩展来简化跨类型的操作。

附录

自定义类型遵循BinaryInteger代码

以下是自定义类型遵循BinaryInteger协议的样例,但是仍然存在报错

Type 'MyInt' does not conform to protocol 'BinaryInteger'

所以,仅作为了解参考

struct MyInt: BinaryInteger {
    private var value: Int

    var magnitude: UInt { UInt(abs(value)) }
    var words: [UInt] { value.words.map { UInt($0) } }
    var bitWidth: Int { value.bitWidth }
    var nonzeroBitCount: Int { value.nonzeroBitCount }
    var leadingZeroBitCount: Int { value.leadingZeroBitCount }
    var trailingZeroBitCount: Int { value.trailingZeroBitCount }

    func hash(into hasher: inout Hasher) {
        hasher.combine(value)
    }

    init<T>(_ source: T) where T: BinaryInteger {
        self.value = Int(source)
    }

    init?<T>(exactly source: T) where T: BinaryInteger {
        guard let value = Int(exactly: source) else {
            return nil
        }
        self.value = value
    }

    init(integerLiteral value: Int) {
        self.value = value
    }

    init<T>(truncatingIfNeeded source: T) where T: BinaryInteger {
        self.value = Int(truncatingIfNeeded: source)
    }

    init<T>(clamping source: T) where T: BinaryInteger {
        self.value = Int(clamping: source)
    }

    init(bitPattern value: UInt) {
        self.value = Int(bitPattern: value)
    }

    static func + (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value + rhs.value)
    }

    static func - (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value - rhs.value)
    }

    static func * (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value * rhs.value)
    }

    static func / (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value / rhs.value)
    }

    static func % (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value % rhs.value)
    }

    static var zero: MyInt { MyInt(0) }

    static prefix func - (operand: MyInt) -> MyInt {
        MyInt(-operand.value)
    }

    static func == (lhs: MyInt, rhs: MyInt) -> Bool {
        lhs.value == rhs.value
    }

    static func < (lhs: MyInt, rhs: MyInt) -> Bool {
        lhs.value < rhs.value
    }

    static func & (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value & rhs.value)
    }

    static func | (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value | rhs.value)
    }

    static func ^ (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value ^ rhs.value)
    }

    static func << (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value << rhs.value)
    }

    static func >> (lhs: MyInt, rhs: MyInt) -> MyInt {
        MyInt(lhs.value >> rhs.value)
    }

    static func <<= (lhs: inout MyInt, rhs: MyInt) {
        lhs = MyInt(lhs.value << rhs.value)
    }

    static func >>= (lhs: inout MyInt, rhs: MyInt) {
        lhs = MyInt(lhs.value >> rhs.value)
    }

    static prefix func ~ (operand: MyInt) -> MyInt {
        MyInt(~operand.value)
    }

    static func += (lhs: inout MyInt, rhs: MyInt) {
        lhs = lhs + rhs
    }

    static func -= (lhs: inout MyInt, rhs: MyInt) {
        lhs = lhs - rhs
    }

    static func *= (lhs: inout MyInt, rhs: MyInt) {
        lhs = lhs * rhs
    }

    static func /= (lhs: inout MyInt, rhs: MyInt) {
        lhs = lhs / rhs
    }

    static func %= (lhs: inout MyInt, rhs: MyInt) {
        lhs = lhs % rhs
    }
}

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注