Scala柯里化函数执行时机问题:Option.fold日志异常原因解析
问题分析:Option.fold中意外触发双日志的原因
两种写法的核心差异
错误写法的问题点
原错误代码的第二个分支:
logAndExecute(s"$key is a triggered key")(storeAndPublishEvent(_))
这里的logAndExecute是柯里化函数,第一个参数列表是普通参数(非传名),第二个是传名参数。当这段代码作为Option.fold的第二个参数时,整个logAndExecute调用会被提前执行——因为fold的第二个参数类型是Event => B,而logAndExecute的返回值就是这个函数类型:
- 第一步:立即求值第一个参数
s"$key is a triggered key",同时执行logger.info(message)打印日志 - 第二步:返回
storeAndPublishEvent(_)这个部分应用函数,作为fold的第二个参数传递
哪怕maybeEvent是None,fold不会调用这个函数,但logAndExecute的第一个参数已经被求值,日志已经打印了,所以会出现两条日志。
正确写法的修复逻辑
修改后的第二个分支:
event => logAndExecute(s"$key is a triggered key")(storeAndPublishEvent(event))
这里把logAndExecute的调用包裹在一个匿名函数event => ...里,作为fold的第二个参数:
- 只有当
maybeEvent是Some(event)时,fold才会调用这个匿名函数 - 此时才会执行
logAndExecute的调用,打印对应日志并执行后续逻辑
关键知识点:Scala参数求值时机
- 普通参数:在函数调用时立即求值,不管后续是否用到
- 传名参数(
=> T):只有在函数内部被调用时才会求值 Option.fold的参数:第一个参数是传名(=> B),第二个参数是普通函数(A => B)——所以第二个参数的表达式会被提前求值,而不是延迟到fold内部调用时
内容的提问来源于stack exchange,提问作者Duc Le
相关产品推荐
相关产品推荐

