【问题标题】:Operator Overloading with Tuples in SwiftSwift 中元组的运算符重载
【发布时间】:2018-05-11 16:09:40
【问题描述】:

运算符重载

Swift 4.1,Xcode 9.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: 如果可以(我认为我可能必须返回 String 来完成此任务),我还想制作一个可以返回精确解的独立二次函数?

额外问题 2: 另外,如果有人知道如何制作一个单独的函数来解决 三次 方程而不是二次方程,那将也值得赞赏。


【问题讨论】:

  • 我不认为一对(大小为 2 的元组)是结果的合适选择。我认为最好使用可以正确建模 3 种情况的枚举:两种解决方案,一种解决方案,零解决方案
  • @Alexander,你认为创建一个包含变量的struct 是个好主意吗:var a1 : Doublevar a2 : Double,然后返回这个struct。另外,这样做有什么好处?
  • 否,因为该结构不能对具有 1 个值或 0 个值的模型进行建模。你需要一个枚举。
  • Numeric 协议没有定义划分。如果您使用 FloatingPoint 代替,那么您的除法运算符将编译。比较stackoverflow.com/q/49899377/1187415

标签: swift function operator-overloading numeric quadratic


【解决方案1】:

Numeric 仅声明 +-* 运算符。 Numeric 中没有 /。您需要BinaryIntegerFloatingPoint 来获得除法。

对于二次方程求解器,我会说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)
    }
}

【讨论】:

  • BinaryIntegerFloatingPoint 有什么区别。另外使用其中一个有什么好处?
  • @NoahWilder 您希望您的解决方案以整数形式出现吗?如果没有,请使用FloatingPoint
  • @NoahWilder 另外,您的第一个额外问题可以作为一个可能很有趣的单独问题提出,因为您已经付出了一些努力。对于第二个,请查看:wikihow.com/Solve-a-Cubic-Equation
【解决方案2】:

关键是在TFloatingPointBinaryInteger 时定义/,而不仅仅是任何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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    相关资源
    最近更新 更多