2015-08-05 4 views
0

В настоящее время я пытаюсь завершить курс Swift на iTunes U, и мы строим калькулятор. У меня возникли проблемы с пониманием части кода.iOS 9 Стэнфордский курс в Swift - лекция 1

Я добавил код ниже, который, как я думал, имеет отношение к файлу.

Вот что меня смущает: почему операция (операнд) вычисляет значение для UnaryOperation (т. Е. Квадратный корень)? Я вижу, что когда класс CalculatorBrain называется, словарь инициализируется, но когда я печатаю словарь, я просто получаю что-то похожее на это: [✕: ✕, -: -, +: +, ⌹: ⌹, √: √ ]. Итак, где/когда программа вычисляет квадратный корень, когда я нажимаю кнопку квадратного корня?

Class CalculatorBrain 
    { 
    private enum Op: Printable 
    { 
    case Operand(Double) 
    case UnaryOperation(String, Double -> Double) 
    case BinaryOperation(String, (Double, Double) -> Double) 

    var description: String { 
     get { 
      switch self { 
      case .Operand(let operand): 
       return "\(operand)" 
      case .UnaryOperation(let symbol, _): 
       return symbol 
      case .BinaryOperation(let symbol, _): 
       return symbol 
      } 
     } 
    } 
} 

private var opStack = [Op]() 

private var knownOps = [String: Op]() 

init() { 
    func learnOp(op: Op) { 
     knownOps[op.description] = op 

    } 
    learnOp(Op.BinaryOperation("✕", *)) 
    learnOp(Op.BinaryOperation("⌹") { $1/$0 }) 
    learnOp(Op.BinaryOperation("+", +)) 
    learnOp(Op.BinaryOperation("-") { $0 - $1 }) 
    learnOp(Op.UnaryOperation ("√", sqrt)) 

} 

private func evaluate(ops: [Op]) -> (result: Double?, remainingOps: [Op]) 
{ 
    if !ops.isEmpty { 
     var remainingOps = ops 
     let op = remainingOps.removeLast() 
     switch op { 
     case .Operand(let operand): 
     return (operand, remainingOps) 
     case .UnaryOperation(_, let operation): 
      let operandEvaluation = evaluate(remainingOps) 
      if let operand = operandEvaluation.result { 
       **return (operation(operand), operandEvaluation.remainingOps)** 
      } 
     // case.BinaryOperation(.....) 
     } 
    } 
    return (nil, ops) 
} 

func evaluate() -> Double? { 
    let (result, remainder) = evaluate(opStack) 
    return result 
} 

func pushOperand(operand: Double) -> Double? { 
    opStack.append(Op.Operand(operand)) 
    return evaluate() 
} 

func performOperation(symbol: String) -> Double? { 
    if let operation = knownOps[symbol] { 
     opStack.append(operation) 
    } 
    return evaluate() 
} 

}

ответ

1

Op enum реализует протокол Printable, что означает, что он имеет description: String. Когда вы печатаете Dictionary, вы отправляете [String : Op] в функцию println, которая затем пытается распечатать Op, используя ее description.

Причина описание операторов такой же, как его ключ в Dictionary потому, что функция learnOp(op: Op) устанавливает ключ быть op.description (knownOps[op.description] = op)

Чтобы увидеть эффект от этого, вы можете добавить новый оператор learnOp(Op.UnaryOperation ("@", sqrt)), который будет напечатан как @:@ внутри словаря knownOps. (А если добавить новую кнопку для оператора @, он также будет выполнять операцию квадратного корня)


Поскольку калькулятор стека на основе операнды получить толкнул, то операции. Когда вызывается evaluate(), он вызывает evaluate(opStack), проходя через весь стек.

evaluate(ops: [Op]) затем берет элемент в стек и оценивает функцию после, рассчитав операнды.

В качестве примера предположим, что вы хотите calucalte sqrt (4 + 5).

Вы бы раздвинуть элементы в стек, и это будет выглядеть так: [ 4, 5, +, sqrt ]

Тогда evaluate(ops: [Op]) видит sqrt и оценивает операнд с рекурсивным вызовом. Затем этот вызов оценивает + с двумя более рекурсивными вызовами, которые возвращают 5 и 4.

Дерево вызовов будет выглядеть следующим образом:

ops: [4, 5, +, sqrt] // Returns sqrt(9) = 3 
      | 
    ops: [4, 5, +]  // Returns 4 + 5 = 9 
     ____|_____ 
    |   | 
ops: [4, 5] ops: [4] 
return 5  return 4 

я настоятельно рекомендую вам поставить точку останова на функцию evaluate() -> Double? и пошагово программу, чтобы увидеть, где она идет с различными операндами и операциями.

+0

Хорошо, отлично, что выяснилось, почему был напечатан словарь, который путь. Спасибо!! Но когда вызывается функция квадратного корня? Я все еще не вижу связи между return (operation (operand), operandEvaluation.remainingOps) – Sami

+0

@Sami Я добавил дополнительную информацию о том, как программа фактически выполняется. –

0
learnOp(Op.UnaryOperation ("√", sqrt)) 

SQRT является встроенной функцией, так что вы учите калькулятор, что "√" означает, что он должен выполнить операцию SQRT.

+0

Хорошо, поэтому я преподаю калькулятор для выполнения операции с квадратным корнем - но когда вызывается операция с квадратным корнем? У меня возникли проблемы с подключением: return (операция (операнд), operandEvaluation.remainingOps) и learnOp (Op.UnaryOperation ("√", sqrt)) – Sami