我目前正在尝试完成iTunes U上的Swift课程,我们正在构建一个计算器。我无法理解部分代码。
我在下面添加了我认为与文件相关的代码。
这让我感到困惑:为什么操作(操作数)会计算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()
}
}
答案 0 :(得分:1)
Op
枚举实现了Printable
协议,这意味着它具有description: String
属性。当您打印Dictionary
时,您将[String : Op]
发送到println
函数,然后尝试使用Op
打印description
。
运算符描述与Dictionary
中的键相同的原因是因为learnOp(op: Op)
函数将键设置为op.description
(knownOps[op.description] = op
)< / p>
要查看此效果,您可以添加一个新的运算符learnOp(Op.UnaryOperation ("@", sqrt))
,该@:@
将在knownOps
字典内打印为@
。 (如果为evaluate()
运算符添加新按钮,它也将执行平方根运算)
由于计算器是基于堆栈的,操作数会被推入,然后是操作。当evaluate(opStack)
被调用时,它会调用evaluate(ops: [Op])
来传递整个堆栈。
[ 4, 5, +, sqrt ]
然后从堆栈中取出to项目,并在计算出操作数后计算函数。
举个例子,假设你想要calucalte sqrt(4 + 5)。
您可以将项目推送到堆栈,它看起来像: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?
我强烈建议你在<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
函数上放一个断点,然后逐步执行程序,看看它在不同的操作数和操作中的位置。
答案 1 :(得分:0)
learnOp(Op.UnaryOperation ("√", sqrt))
sqrt是一个内置功能,所以你要教导计算器&#34;√&#34;意味着它应该执行sqrt操作。