iOS 9 斯坦福课程 Swift - 第 1 讲

iOS 9 Stanford Course in Swift - Lecture 1

我目前正在努力完成 iTunes U 上的 Swift 课程,我们正在构建一个计算器。我无法理解部分代码。

我在下面添加了我认为与文件相关的代码。

让我感到困惑的是:为什么 operation(operand) 会计算 UnaryOperation 的值(即平方根)?我看到当 CalculatorBrain class 被调用时,字典被初始化,但是当我打印字典时,我只得到如下内容:[✕: ✕, -: -, +: +, ????: ???? ,√:√]。那么 where/when 当我点击平方根按钮时程序会计算平方根吗?

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("⌹") {  / [=12=] })
    learnOp(Op.BinaryOperation("+", +))
    learnOp(Op.BinaryOperation("-") { [=12=] -  })
    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()
}

}

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

sqrt 是一个内置函数,因此您是在教计算器“√”表示它应该执行 sqrt 运算。

Op 枚举实现了 Printable 协议,这意味着它有一个 description: String 属性。当您打印 Dictionary 时,您将 [String : Op] 发送到 println 函数,该函数然后尝试使用其 description.

打印 Op

运算符的描述与Dictionary中的键相同的原因是因为learnOp(op: Op)函数将键设置为op.descriptionknownOps[op.description] = op )

要查看其效果,您可以添加一个新运算符 learnOp(Op.UnaryOperation ("@", sqrt)),它将在 knownOps 词典中打印为 @:@。 (而且如果你为 @ 运算符添加一个新按钮,它也会执行平方根运算)


由于计算器是基于堆栈的,因此操作数被推入,然后是操作。当 evaluate() 被调用时,它调用 evaluate(opStack) 传递整个堆栈。

evaluate(ops: [Op]) 然后从堆栈中取出 to 项并在 计算完操作数后计算函数

例如,假设您要计算 sqrt(4 + 5)。

您将把项目压入堆栈,它看起来像:[ 4, 5, +, sqrt ]

然后 evaluate(ops: [Op]) 看到 sqrt 并通过递归调用计算操作数。然后,该调用使用 return 54.

两个递归调用评估 +

呼叫树看起来像这样:

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? 函数上放置一个断点,然后单步执行程序以查看不同操作数和操作的执行情况。