You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:27:44