在 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 协议是一种标准做法。