问题描述
我正试图利用
uproot.rootio.TH2D
但它会引发Arrayindexoutofboundsexception
update tTable
set text_modified=replace(text_nvarchar,'bonus_score',bonus_score);
因为
infix fun <T> Boolean.then(param: T): T? = if (this) param else null
我如何使其在Kotlin中工作?
解决方法
在Kotlin中,会急切地评估函数参数:调用函数时,会在将控制权传递给函数之前计算出每个参数的值。无论是否在函数中使用该值,都会发生这种情况。 (毕竟,通常在不实际运行代码的情况下,您不能告诉是否使用它。 * )
(对于infix函数和标准调用来说都是正确的;尽管语法不同,但含义完全相同。)
事实上,对于大多数其他运算符也是如此:当您添加两个数字,连接两个字符串,从函数返回值或其他任何操作时,将首先对每个操作数求值。仅有少数例外,其中短路&&
和||
运算符最为明显。
因此,在您的情况下,诸如then data[index - 1].id
之类的调用将始终首先评估data[index - 1].id
,然后再将其传递给then()
函数;因此,如果index
为0,则将抛出ArrayIndexOutOfBoundsException。
如果您不希望对其进行评估,则必须传递一个lambda,例如:
infix fun <T> Boolean.then(lazyValue: () -> T): T?
= if (this) lazyValue() else null
然后您可以像这样使用它:
(index > 0) then { data[index - 1].id }
发生的事情是对代码进行了评估,给出了一个lambda,并将其作为lazyValue
传递给函数;但是除非/ until * 到达函数中的lazyValue()
,否则不评估lambda的内容。
您可以在诸如require(value,lazyMessage)
之类的库函数中看到此模式;由于几乎总是可以满足该要求,并且消息通常是在运行时必须构造的复杂字符串,因此仅在条件为false时,才通过评估其第二个参数来避免创建不必要的String对象。
传递lambda的不利之处在于它的效率略低:它需要创建一个对象来表示lambda,从而增加了一点额外的CPU和堆。 (视情况而定,它可能每次都需要创建一个新对象,或者可能能够重用同一对象。)
但是Kotlin提供了一种解决方法:如果将函数标记为inline
,则它既避免了函数调用又避免了lambda,并有效地将代码直接“粘贴”到函数的内联副本中,就像您用手“写出”函数体一样高效。
(**有一个名为contracts的实验性功能,可让您告诉编译器您是否确定在什么情况下会评估lambda。 避免某些类型的警告或错误-尽管它不会改变评估顺序,所以您在这里仍然需要一个lambda。)