使用Expression开发计算器遇下标仅可读错误,求原因解析
嘿,这个问题我熟!咱们先从你代码里的关键细节说起——
问题根源:你的字典是「只读常量」
你声明mathSymbols用的是public static let,这意味着这个字典是不可变的常量。虽然你在初始化闭包里用var symbols临时构建字典、添加默认函数,但当闭包执行完,mathSymbols就被绑定成了一个只读的字典实例。之后再想通过mathSymbols[新函数] = 求值逻辑这种下标赋值的方式加新功能,自然会触发「下标仅可读」的错误——毕竟常量字典的下标只支持读,不支持写嘛。
两种搞定的方案,按需选就行
方案1:把字典改成可变变量(var)
如果需要在程序运行时动态添加/修改函数(比如根据用户需求扩展功能),直接把let换成var就OK:
public static var mathSymbols: [Symbol: SymbolEvaluator] = { var symbols: [Symbol: SymbolEvaluator] = [:] symbols[.function("atan", arity: 1)] = { atan($0[0]) } symbols[.function("abs", arity: 1)] = { abs($0[0]) } // 先把默认函数加好 return symbols }()
之后你就能随便加自定义函数或者类型转换函数了:
// 加个自定义平方函数 mathSymbols[.function("square", arity: 1)] = { $0[0] * $0[0] } // 加个转整数的类型转换函数 mathSymbols[.function("toInt", arity: 1)] = { Double(Int($0[0])) }
⚠️ 小提醒:如果是多线程环境下操作这个静态变量,记得加个线程锁(比如NSLock),避免多个线程同时修改导致的竞态问题。
方案2:初始化时一次性塞完所有函数
如果你的自定义函数不需要动态添加,只是一开始漏写了,那直接把所有函数都写到初始化闭包里就行,继续保持let不变(这种方式更安全,不会被意外修改):
public static let mathSymbols: [Symbol: SymbolEvaluator] = { var symbols: [Symbol: SymbolEvaluator] = [:] // 默认函数 symbols[.function("atan", arity: 1)] = { atan($0[0]) } symbols[.function("abs", arity: 1)] = { abs($0[0]) } // 自定义函数和转换函数直接加在这里 symbols[.function("customAdd", arity: 2)] = { $0[0] + $0[1] * 2 } symbols[.function("toString", arity: 1)] = { // 这里可以写字符串转换逻辑,比如把数字转成带格式的字符串再转回Double(根据你的需求调整) Double(String(format: "%.2f", $0[0])) ?? $0[0] } return symbols }()
额外踩坑提醒:别搞错函数的参数数量
添加自定义函数时,一定要确保.function的arity参数和你的求值闭包接收的参数数量一致——比如arity设为2,闭包里就要用$0[0]和$0[1],不然运行时会出现参数不匹配的错误,这也是Expression框架里新手容易踩的小坑哦。
内容的提问来源于stack exchange,提问作者Anters Bear
相关产品推荐
相关产品推荐

