Swift 中的元组运算符重载
Operator Overloading with Tuples in Swift
运算符重载
Swift4.1,Xcode9.3
我正在尝试在 Swift 中生成二次方程函数。
在处理此问题时,我发现我需要重载一些运算符,以便我可以与其他数字一起使用元组(在本例中为 Double
),这是因为我需要使用我的自定义 ±
运算符。尽管我在我的二次函数中只使用类型 Double
的值,但我决定我想使用泛型来使我的重载运算符更灵活以供将来使用。
但是——出于我不明白的原因——我收到关于重载 /
运算符声明的错误。
自定义 ±
操作员 - 工作
infix operator ± : AdditionPrecedence
public func ± <T: Numeric>(left: T, right: T) -> (T, T) {
return (left + right, left - right)
}
二次函数 - 有效
func quadratic(a: Double, b: Double, c: Double) -> (Double, Double) {
return (-b ± sqrt((b * b) - (4 * a * c))) / (2 * a)
}
运算符过载 - 部分工作¹
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 / rhs, lhs.1 / rhs)
}
func * <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 * rhs, lhs.1 * rhs)
}
func - <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 - rhs, lhs.1 - rhs)
}
func + <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 + rhs, lhs.1 + rhs)
}
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs / rhs.0, lhs / rhs.1)
}
func * <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs * rhs.0, lhs * rhs.1)
}
func - <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs - rhs.0, lhs - rhs.1)
}
func + <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs + rhs.0, lhs + rhs.1)
}
1. 我只在使用 /
运算符时收到这些错误,而不会收到任何其他重载运算符 (+
, -
, 或 *
).
有错误的重载运算符(/
s)- 不工作
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 / rhs, lhs.1 / rhs)
}
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs / rhs.0, lhs / rhs.1)
}
假设: 我认为我在重载 /
运算符本身的声明——尽管它在不同的上下文中使用——导致了错误。
最终问题:
如何在解决错误的同时仍然保持重载运算符的灵活性?
奖金问题 1: 如果可以(我想我可能必须 return a String
来完成这个),我还想制作一个单独的二次函数,它可以 return 一个 exact 解决方案?
奖金问题 2: 此外,如果有人知道如何制作一个单独的函数来解决 三次 方程而不是二次方程,那也将不胜感激。
Numeric
only declares +
, -
and *
operators. There is no /
in Numeric
. You need either BinaryInteger
or FloatingPoint
得到除法
对于二次方程求解器,我会说FloatingPoint
更合适:
func / <T: FloatingPoint>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs / rhs.0, lhs / rhs.1)
}
func / <T: FloatingPoint>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 / rhs, lhs.1 / rhs)
}
正如亚历山大所说,如果您创建一个代表解决方案的枚举会更好:
enum QuadraticSolution {
case none
case one(value: Double)
case two(value1: Double, value2: Double)
}
func quadratic(a: Double, b: Double, c: Double) -> QuadraticSolution {
let discriminant = (b * b) - (4 * a * c)
switch discriminant {
case 0:
return .one(value: -b / (2 * a))
case let x where x < 0:
return .none
default:
let twoSolutions = (-b ± sqrt(discriminant)) / (2 * a)
return .two(value1: twoSolutions.0, value2: twoSolutions.1)
}
}
关键是当 T
是 FloatingPoint
或 BinaryInteger
时定义 /
,而不仅仅是任何 Numeric
。此外,我建议您使用枚举来正确模拟二次函数的三种可能结果:
import Foundation
infix operator ± : AdditionPrecedence
public enum QuadraticRoots<T> {
case two(T, T)
case one(T)
case none
func applyWithSelfOnLeft(_ fn: (T, T) -> T, withOperand value: T) -> QuadraticRoots {
switch self {
case let .two(a, b): return .two(fn(a, value), fn(b, value))
case let .one(a): return .one(fn(a, value))
case .none: return .none
}
}
func applyWithSelfOnRight(withOperand value: T, _ fn: (T, T) -> T) -> QuadraticRoots {
switch self {
case let .two(a, b): return .two(fn(value, a), fn(value, b))
case let .one(a): return .one(fn(value, a))
case .none: return .none
}
}
}
public func ± <T: Numeric>(left: T, right: T) -> QuadraticRoots<T> {
return QuadraticRoots.two(left + right, left - right)
}
extension QuadraticRoots where T: Numeric {
static func + (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((+), withOperand: rhs)
}
static func - (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((-), withOperand: rhs)
}
static func * (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((*), withOperand: rhs)
}
static func + (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (+))
}
static func - (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (-))
}
static func * (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (*))
}
static func discriminantOf(xSquared a: T, x b: T, c: T) -> T { return b*b - 4*a*c }
}
extension QuadraticRoots where T: FloatingPoint {
static func / (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((/), withOperand: rhs)
}
static func / (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (/))
}
static func solveFrom(xSquared a: T, x b: T, c: T) -> QuadraticRoots {
let discriminant = self.discriminantOf(xSquared: a, x: b, c: c)
return (-b ± sqrt(discriminant)) / (2 * a)
}
}
let a = 5 ± 10
print(a)
print(a + 2)
print(a - 2)
print(a * 2)
print(2 + a)
print(2 - a)
print(2 * a)
//print(a / 2)
运算符重载
Swift4.1,Xcode9.3
我正在尝试在 Swift 中生成二次方程函数。
在处理此问题时,我发现我需要重载一些运算符,以便我可以与其他数字一起使用元组(在本例中为 Double
),这是因为我需要使用我的自定义 ±
运算符。尽管我在我的二次函数中只使用类型 Double
的值,但我决定我想使用泛型来使我的重载运算符更灵活以供将来使用。
但是——出于我不明白的原因——我收到关于重载 /
运算符声明的错误。
自定义 ±
操作员 - 工作
infix operator ± : AdditionPrecedence
public func ± <T: Numeric>(left: T, right: T) -> (T, T) {
return (left + right, left - right)
}
二次函数 - 有效
func quadratic(a: Double, b: Double, c: Double) -> (Double, Double) {
return (-b ± sqrt((b * b) - (4 * a * c))) / (2 * a)
}
运算符过载 - 部分工作¹
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 / rhs, lhs.1 / rhs)
}
func * <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 * rhs, lhs.1 * rhs)
}
func - <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 - rhs, lhs.1 - rhs)
}
func + <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 + rhs, lhs.1 + rhs)
}
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs / rhs.0, lhs / rhs.1)
}
func * <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs * rhs.0, lhs * rhs.1)
}
func - <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs - rhs.0, lhs - rhs.1)
}
func + <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs + rhs.0, lhs + rhs.1)
}
1. 我只在使用 /
运算符时收到这些错误,而不会收到任何其他重载运算符 (+
, -
, 或 *
).
有错误的重载运算符(/
s)- 不工作
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 / rhs, lhs.1 / rhs)
}
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs / rhs.0, lhs / rhs.1)
}
假设: 我认为我在重载 /
运算符本身的声明——尽管它在不同的上下文中使用——导致了错误。
最终问题:
如何在解决错误的同时仍然保持重载运算符的灵活性?
奖金问题 1: 如果可以(我想我可能必须 return a String
来完成这个),我还想制作一个单独的二次函数,它可以 return 一个 exact 解决方案?
奖金问题 2: 此外,如果有人知道如何制作一个单独的函数来解决 三次 方程而不是二次方程,那也将不胜感激。
Numeric
only declares +
, -
and *
operators. There is no /
in Numeric
. You need either BinaryInteger
or FloatingPoint
得到除法
对于二次方程求解器,我会说FloatingPoint
更合适:
func / <T: FloatingPoint>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs / rhs.0, lhs / rhs.1)
}
func / <T: FloatingPoint>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 / rhs, lhs.1 / rhs)
}
正如亚历山大所说,如果您创建一个代表解决方案的枚举会更好:
enum QuadraticSolution {
case none
case one(value: Double)
case two(value1: Double, value2: Double)
}
func quadratic(a: Double, b: Double, c: Double) -> QuadraticSolution {
let discriminant = (b * b) - (4 * a * c)
switch discriminant {
case 0:
return .one(value: -b / (2 * a))
case let x where x < 0:
return .none
default:
let twoSolutions = (-b ± sqrt(discriminant)) / (2 * a)
return .two(value1: twoSolutions.0, value2: twoSolutions.1)
}
}
关键是当 T
是 FloatingPoint
或 BinaryInteger
时定义 /
,而不仅仅是任何 Numeric
。此外,我建议您使用枚举来正确模拟二次函数的三种可能结果:
import Foundation
infix operator ± : AdditionPrecedence
public enum QuadraticRoots<T> {
case two(T, T)
case one(T)
case none
func applyWithSelfOnLeft(_ fn: (T, T) -> T, withOperand value: T) -> QuadraticRoots {
switch self {
case let .two(a, b): return .two(fn(a, value), fn(b, value))
case let .one(a): return .one(fn(a, value))
case .none: return .none
}
}
func applyWithSelfOnRight(withOperand value: T, _ fn: (T, T) -> T) -> QuadraticRoots {
switch self {
case let .two(a, b): return .two(fn(value, a), fn(value, b))
case let .one(a): return .one(fn(value, a))
case .none: return .none
}
}
}
public func ± <T: Numeric>(left: T, right: T) -> QuadraticRoots<T> {
return QuadraticRoots.two(left + right, left - right)
}
extension QuadraticRoots where T: Numeric {
static func + (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((+), withOperand: rhs)
}
static func - (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((-), withOperand: rhs)
}
static func * (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((*), withOperand: rhs)
}
static func + (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (+))
}
static func - (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (-))
}
static func * (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (*))
}
static func discriminantOf(xSquared a: T, x b: T, c: T) -> T { return b*b - 4*a*c }
}
extension QuadraticRoots where T: FloatingPoint {
static func / (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((/), withOperand: rhs)
}
static func / (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (/))
}
static func solveFrom(xSquared a: T, x b: T, c: T) -> QuadraticRoots {
let discriminant = self.discriminantOf(xSquared: a, x: b, c: c)
return (-b ± sqrt(discriminant)) / (2 * a)
}
}
let a = 5 ± 10
print(a)
print(a + 2)
print(a - 2)
print(a * 2)
print(2 + a)
print(2 - a)
print(2 * a)
//print(a / 2)