Проблема с рекурсивными перечислениями в Swift 5.1 - PullRequest
2 голосов
/ 01 апреля 2020

Я изучаю рекурсивные перечисления в Swift 5.1 с документацией Swift.

Вот код.

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))

Screen

Я думаю, что-то происходит неправильно в последней строке кода.

Что это значит?

1 Ответ

2 голосов
/ 01 апреля 2020

evaluate(_:) - это функция экземпляра из ArithmeticExpression, т.е. вы должны вызывать ее для экземпляра ArithmeticExpression (с этим экземпляром является то, к чему относится self к). Тип 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. Либо сделать эту функцию обычной c. Функция stati c не вызывается для экземпляра, она вызывается непосредственно для типа, как вы пытались сделать:

    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())
    

    Я бы сказал, что это, вероятно, более "идиоматическая c" версия.

...