Swift支持数值操作Numeric协议
Swift支持数值操作Numeric协议

Swift支持数值操作Numeric协议

在 Swift 中,Numeric 是一个协议,用来描述支持数值操作的类型。Numeric 是数值类型(例如 Int、Double 和 Float)的基础协议,其主要目的是提供通用的接口来支持基本的数值运算。

Numeric 协议的核心内容

协议继承

Numeric 继承自 AdditiveArithmetic 协议,因此它必须支持加法和减法操作,并定义一个 zero 属性。

protocol Numeric: AdditiveArithmetic {
    associatedtype Magnitude: Comparable

    var magnitude: Magnitude { get }
    init?<T>(exactly source: T) where T : BinaryInteger

    static func * (lhs: Self, rhs: Self) -> Self
    static func *= (lhs: inout Self, rhs: Self)
}

必须实现的内容

1、加法和减法

由于继承自 AdditiveArithmetic,必须实现 + 和 – 运算符,以及静态属性 zero。

2、乘法

* 运算符:定义两个数值的乘积。

*= 运算符:支持对当前值进行乘法赋值。

3、magnitude 属性

表示数值的绝对值。例如,对于整数 -5,其 magnitude 是 5。

4、可选初始化器 init?<T>(exactly source: T)

允许从一个整数类型(BinaryInteger)安全地初始化为当前类型。如果无法表示该值,初始化会失败并返回 nil。

系统中遵循 Numeric 的类型

以下类型都默认遵循 Numeric 协议:

整数类型

Int, UInt

Int8, Int16, Int32, Int64

UInt8, UInt16, UInt32, UInt64

浮点数类型

Float, Double, Float80

这些类型已经提供了 Numeric 所需的所有实现。

使用场景

Numeric 协议使得可以编写泛型代码,用于操作任何符合数值操作要求的类型。例如:

实现一个泛型求和函数

func add<T: Numeric>(_ a: T, _ b: T) -> T {
    return a + b
}

print(add(3, 5))         // 输出 8
print(add(3.5, 2.1))     // 输出 5.6

结合 magnitude 使用

func compareByMagnitude<T: Numeric>(_ a: T, _ b: T) -> Bool {
    return a.magnitude < b.magnitude
}

print(compareByMagnitude(-3, 5))     // 输出 true
print(compareByMagnitude(-10, 7))    // 输出 false

在 Swift 中,magnitude 是 Numeric 协议中定义的一个属性,用来表示一个数值的大小(通常是绝对值)。它是一个只读属性,返回值的类型是 Self.Magnitude,可以是相应类型的绝对值或者等价的概念。

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

自定义类型遵循 Numeric

如果有自己的数值类型,可以让它符合 Numeric 协议,前提是实现协议要求的所有内容。

示例:自定义复数类型

struct Complex: Numeric, ExpressibleByIntegerLiteral {
    var real: Double
    var imaginary: Double

    var magnitude: Double {
        return (real * real + imaginary * imaginary).squareRoot()
    }

    static var zero: Complex {
        return Complex(real: 0, imaginary: 0)
    }

    init(real: Double, imaginary: Double) {
        self.real = real
        self.imaginary = imaginary
    }

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

    // 实现 ExpressibleByIntegerLiteral 所需的初始化器
    init(integerLiteral value: Int) {
        self.real = Double(value)
        self.imaginary = 0
    }

    static func + (lhs: Complex, rhs: Complex) -> Complex {
        return Complex(real: lhs.real + rhs.real, imaginary: lhs.imaginary + rhs.imaginary)
    }

    static func - (lhs: Complex, rhs: Complex) -> Complex {
        return Complex(real: lhs.real - rhs.real, imaginary: lhs.imaginary - rhs.imaginary)
    }

    static func * (lhs: Complex, rhs: Complex) -> Complex {
        return Complex(
            real: lhs.real * rhs.real - lhs.imaginary * rhs.imaginary,
            imaginary: lhs.real * rhs.imaginary + lhs.imaginary * rhs.real
        )
    }

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

// 测试逻辑封装在函数中
func testComplex() {
    let c1 = Complex(real: 3, imaginary: 4)
    let c2 = Complex(real: 1, imaginary: 2)
    let sum = c1 + c2
    print(sum) // Complex(real: 4.0, imaginary: 6.0)

    // 测试字面量初始化
    let c3: Complex = 5
    print(c3) // Complex(real: 5.0, imaginary: 0.0)
}

// 调用测试函数
testComplex()

总结

Numeric 协议为数值类型定义了统一的接口,支持基本的加减乘运算以及从整数转换的能力。在泛型编程中,Numeric 是非常强大的工具,用于编写与具体数值类型无关的代码。如果要实现自定义数值类型,遵循 Numeric 协议是一种标准做法。

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

发表回复

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