Kotlin 中缀参数即使未在函数体中调用也要计算

Kotlin 中缀参数即使未在函数体中调用也要计算,kotlin,ternary,infix-notation,Kotlin,Ternary,Infix Notation,我正试图利用这个机会 infix fun <T> Boolean.then(param: T): T? = if (this) param else null 自 如何使其在Kotlin中工作?在Kotlin中,函数参数被急切地评估:当调用函数时,在将控制权传递给函数之前,每个参数的值都被计算出来。无论该值是否会在函数中使用,都会发生这种情况(毕竟,通常在没有实际运行代码的情况下,您无法判断是否会使用它。*) (中缀函数和标准调用都是如此;尽管语法不同,但含义完全相同。) 事实上,

我正试图利用这个机会

infix fun <T> Boolean.then(param: T): T? = if (this) param else null


如何使其在Kotlin中工作?

在Kotlin中,函数参数被急切地评估:当调用函数时,在将控制权传递给函数之前,每个参数的值都被计算出来。无论该值是否会在函数中使用,都会发生这种情况(毕竟,通常在没有实际运行代码的情况下,您无法判断是否会使用它。*)

(中缀函数和标准调用都是如此;尽管语法不同,但含义完全相同。)

事实上,大多数其他运算符也是如此:当您添加两个数字、串联两个字符串、从函数返回值或其他任何操作时,首先计算每个操作数。只有少数例外情况,其中短路
&&
|
运算符最为明显

因此,在您的情况下,像
then data[index-1].id
这样的调用在将其传递给
then()
函数之前总是首先计算
data[index-1].id
;因此,如果
index
为0,则会抛出ArrayIndexOutOfBoundsException,如您所见

如果不希望对其进行评估,则必须传递lambda,例如:

infix fun <T> Boolean.then(lazyValue: () -> T): T?
        = if (this) lazyValue() else null
这里发生的情况是,对代码求值,给出一个lambda,作为
lazyValue
传递给函数;但是lambda的内容不会求值,除非/直到*它到达函数中的
lazyValue()

您可以在库函数中看到这种模式,例如;由于需求几乎总是会得到满足,并且消息通常是一个复杂的字符串,必须在运行时构造,因此只有在条件为false时才对其第二个参数求值,从而避免创建不必要的字符串对象

传递lambda的缺点是效率稍低:它需要创建一个对象来表示lambda,这样就增加了一点额外的CPU和堆(根据具体情况,它可能每次都需要创建一个新对象,或者可以重用同一个对象)

但是Kotlin提供了一种解决方法:如果将函数标记为,那么它将避免函数调用和lambda,并有效地将代码直接“粘贴”到函数的内联副本中,使其与“手工”写出函数体一样高效



(*有一个名为的实验特性,它可以让您告诉编译器您是否确实知道在什么情况下会对lambda进行求值。这可能会避免某些类型的警告或错误-尽管它不会更改求值顺序,因此您仍然需要lambda。)

由于调用函数参数时会读取函数参数,因此在检查布尔值之前会调用
数据[index-1]
。您需要将
param
更改为lambda,以便在检查布尔值之后可以调用。谢谢您的提示。
data[-1] doesn't exist.
infix fun <T> Boolean.then(lazyValue: () -> T): T?
        = if (this) lazyValue() else null
(index > 0) then { data[index - 1].id }