Julia的do-block语法为何将代码块传入不同参数位置?
Julia do-block 传参规则
do-block的传参逻辑从语法层面是完全固定的,不存在“根据场景切换传参位置”的情况:所有跟在函数调用后的do代码块,都会被解析为一个匿名函数,永远作为本次函数调用的第一个实参传入。你观察到的位置差异,本质是混淆了不同函数的多态方法签名造成的错觉。
两个示例的实际展开逻辑
自定义函数my_function示例
你定义的函数签名为my_function(f, container),第一个形参就是用来接收遍历元素时调用的处理函数:
my_function(f, container) = begin for element in container f(element) end return nothing end
对应的do-block写法:
my_function([1,2,3]) do x print(x) end
语法糖展开后和以下写法完全等价,完全符合do块作为第一个参数的规则:
my_function(function(x) print(x) end, [1,2,3])
标准库get函数示例
这里的认知偏差来自对get多方法的混淆:
- 你记忆中
get(Dictionary_name, Key_name, Default Value)是接收静态默认值的方法,这个方法的第三个参数是具体值而非函数,本身不支持do-block调用 - 支持惰性计算默认值、适配do-block写法的是
get的另一个独立方法,它的签名本来就是get(default_calculator::Function, dict, key),第一个形参专门用来接收“key不存在时才执行的默认值计算函数”,设计目的就是避免key存在时还白白执行默认值计算逻辑产生额外开销。
你写的do-block调用:
get(dict, key) do time() end
语法糖展开后实际是以下形式,do块生成的匿名函数依然在第一个实参位置,并没有传到参数列表末尾:
get(function() time() end, dict, key)
设计逻辑说明
Julia生态中所有支持do-block写法的函数,都会刻意把“接收处理逻辑的函数形参”放在参数列表的第一位,和语法规则对齐。这种设计的好处是写代码时,括号内只需要传入文件名、集合、字典这类实体参数,大段的逻辑处理块接在括号后面,阅读时不会被长函数定义打断参数列表的连贯性,比如常见的open、map、foreach等函数的do-block写法,全都是遵循这个设计逻辑:
# open的方法签名是 open(f::Function, filename, mode) open("test.txt", "w") do io write(io, "hello") end # 展开后是 open(function(io) write(io,"hello") end, "test.txt", "w")
内容的提问来源于stack exchange,提问作者TylerD
相关产品推荐
相关产品推荐

