【问题标题】:Problem with recursive enums in Swift 5.1Swift 5.1 中的递归枚举问题
【发布时间】:2020-04-01 13:16:56
【问题描述】:

我正在使用 Swift 文档在 Swift 5.1 中学习递归枚举。

这是一个代码。

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)

    func evaluate(_ expression: ArithmeticExpression) -> Int {
        switch expression {
        case let .number(value):
            return value
        case let .addition(left, right):
            return evaluate(left) + evaluate(right)
        case let .multiplication(left, right):
            return evaluate(left) * evaluate(right)
        }
    }
}

let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

print(ArithmeticExpression.evaluate(product))

我认为最后一行代码出了点问题。

这是什么意思?

【问题讨论】:

  • 提示:了解静态(类型)方法和实例方法之间的区别。
  • 控制台未打印lldb_expr_5。控制台根据你的截图打印(Function)
  • lldb_expr_5 是 Playground 正在构建您的代码的 swift 模块的名称。 Swift 代码必须存在于模块中,因此 Playground(和 REPL)必须为其命名,我们选择 lldb_expr... 5 是因为 Playground 中的每个“提交”代码都会编译成不同的模块。这是为了帮助我们处理重新定义,这在 Playground 和 REPL 中是有用的,但在单个模块中是不允许的。模块名称是类全名的一部分,这就是您在此输出中看到它的原因。它与您的问题无关。

标签: swift xcode enums console lldb


【解决方案1】:

evaluate(_:)ArithmeticExpression实例函数,也就是说,您必须将其称为on ArithmeticExpression 的实例(该实例就是@987654324 @指)。 evaluate(_:) 的类型是(ArithmeticExpression) -> Int

Swift 允许您在类型上调用实例函数。你得到的是一个未绑定的实例函数。也就是说,一个没有值绑定的函数作为它的self 值。这就是您自己运行ArithmeticExpression.evaluate 时所做的事情。返回的未绑定实例函数的类型为:

(ArithmeticExpression) -> (ArithmetricExpression) -> Int
// ^---  the "self"        ^--- the "expression" param ^--- the final return value.

通过调用它并提供product 作为参数(ArithmeticExpression.evaluate(product)),你得到的是一个(ArithmeticExpression) -> Int 类型的函数。此函数是一个绑定实例函数,即self 现在已绑定(它现在的值为product),但它正在等待再次调用,另一个ArithmeticExpression 作为论据。

有两种方法可以解决这个问题以实现您想要的:

  1. 要么让它成为一个静态函数。静态函数不会在实例上调用,而是直接在类型上调用,就像您尝试做的那样:

    indirect enum ArithmeticExpression {
        case number(Int)
        case addition(ArithmeticExpression, ArithmeticExpression)
        case multiplication(ArithmeticExpression, ArithmeticExpression)
    
        // Make it static here
        static func evaluate(_ expression: ArithmeticExpression) -> Int {
            switch expression {
            case let .number(value):
                return value
            case let .addition(left, right):
                return evaluate(left) + evaluate(right)
            case let .multiplication(left, right):
                return evaluate(left) * evaluate(right)
            }
        }
    }
    
    let five = ArithmeticExpression.number(5)
    let four = ArithmeticExpression.number(4)
    let sum = ArithmeticExpression.addition(five, four)
    let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
    
    print(ArithmeticExpression.evaluate(product))
    
  2. evaluate 保留为实例函数,但直接在您要评估的实例上调用它,而不是在类型上。由于self 将是您感兴趣的表达式,因此您不再需要expression 参数:

    indirect enum ArithmeticExpression {
        case number(Int)
        case addition(ArithmeticExpression, ArithmeticExpression)
        case multiplication(ArithmeticExpression, ArithmeticExpression)
    
        func evaluate() -> Int {
            switch self {
            case let .number(value):
                return value
            case let .addition(left, right):
                return left.evaluate() + right.evaluate()
            case let .multiplication(left, right):
                return left.evaluate() * right.evaluate()
            }
        }
    }
    
    let five = ArithmeticExpression.number(5)
    let four = ArithmeticExpression.number(4)
    let sum = ArithmeticExpression.addition(five, four)
    let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
    
    print(product.evaluate())
    

    我会说这可能是更“惯用”的版本。

【讨论】:

  • 点赞 |产品评估(产品) | ?
  • @Sam You 可以 这样做,但这毫无意义。要么将product 作为self 传递(通过使evaluate 成为实例函数,并在实例product 上调用它),或者将其作为参数传递,但不要同时进行。对了,你可以用back ticks to format code like this
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多