此代码编译时出现警告(对性能影响不显着):
inline fun test(noinline f: () -> Unit) {
thread(block = f)
}
Run Code Online (Sandbox Code Playgroud)此代码无法编译(非法使用inline-parameter):
inline fun test(crossinline f: () -> Unit) {
thread(block = f)
}
Run Code Online (Sandbox Code Playgroud)此代码编译时出现警告(对性能影响不显着):
inline fun test(noinline f: () -> Unit) {
thread { f() }
}
Run Code Online (Sandbox Code Playgroud)此代码编译时没有警告或错误:
inline fun test(crossinline f: () -> Unit) {
thread { f() }
}
Run Code Online (Sandbox Code Playgroud)这是我的问题:
noinline和之间究竟有什么区别crossinline?mac*_*usz 37
从内联函数参考:
请注意,某些内联函数可能会将传递给它们的lambda作为参数调用,而不是直接来自函数体,而是来自另一个执行上下文,例如本地对象或嵌套函数.在这种情况下,lambda中也不允许非本地控制流.为了表明,lambda参数需要用crossinline修饰符标记
因此,示例2.不编译,因为crossinline仅强制执行本地控制流,并且表达式block = f违反了该控制流.示例1编译,因为noinline不需要这样的行为(显然,因为它是一个普通的函数参数).
示例1和3不会产生任何性能改进,因为唯一的lambda参数被标记noinline,使得inline函数的修饰符无用且冗余 - 编译器想要内联某些东西,但是所有可能已被标记为不内联的内容.
考虑两个函数,A和B.
inline fun test(noinline f: () -> Unit) {
thread { f() }
}
Run Code Online (Sandbox Code Playgroud)
fun test(f: () -> Unit) {
thread { f() }
}
Run Code Online (Sandbox Code Playgroud)
函数A的行为类似于函数B,因为参数f不会被内联(B函数不会内联主体,test而在A函数中,正文:thread { f() }仍然被内联).
现在,在示例4中不是这样,因为crossinline f: () -> Unit参数可以内联,它不能违反前面提到的非本地控制流规则(比如将新值分配给全局变量).如果可以内联,则编译器会假设性能得到改进,并且不会像示例3中那样发出警告.
Mar*_*nik 11
让我向您展示每个示例命令编译器执行的操作,而不是冗长的解释.我们先写一些使用你的函数的代码:
fun main(args: Array<String>) {
test {
println("start")
println("stop")
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们来看看你的变种.
test1,test4inline fun test1(noinline f: () -> Unit) {
thread(block = f)
}
fun compiledMain1() {
val myBlock = {
println("start")
println("stop")
}
thread(block = myBlock)
}
Run Code Online (Sandbox Code Playgroud)
首先,请注意,没有证据证明main存在.内联函数并没有真正"被调用":就好像代码noinline是在里面写的block = f.另一方面,inline fun test1lambda参数的行为与没有内联的行为相同:创建一个lambda对象并将其传递给test1函数.
main(),noinlineinline fun test2(crossinline f: () -> Unit) {
thread(block = f)
}
fun compiledMain2() {
thread(block =
println("start")
println("stop")
)
}
Run Code Online (Sandbox Code Playgroud)
我希望我能想到这里发生的事情:你要求将块的代码复制粘贴到一个需要值的地方.这只是语法垃圾.原因:无论thread是否请求将块复制粘贴到使用它的位置.这个修饰符只限制你在块内写的东西(没有crossinline等等)
block = f,crossinlineinline fun test3(noinline f: () -> Unit) {
thread { f() }
}
fun compiledMain3() {
val myBlock = {
println("start")
println("stop")
}
thread { myBlock() }
}
Run Code Online (Sandbox Code Playgroud)
我们回到return这里,所以事情再次简单明了.您创建一个常规的lambda对象noinline,然后创建另一个委托给它的常规lambda对象:{ f() }然后将其传递给noinline.
myBlock,{ myBlock() }inline fun test4(crossinline f: () -> Unit) {
thread { f() }
}
fun compiledMain4() {
thread {
println("start")
println("stop")
}
}
Run Code Online (Sandbox Code Playgroud)
最后,这个例子演示了什么thread().的代码crossinline被内联到{ f() },块的代码被内联到使用它的地方.但是,由于它在常规lambda对象的定义中使用,因此它不能包含非本地控制流.
Kotlin团队希望您明智地使用内联功能.通过内联,编译代码的大小可以显着爆炸,甚至可以达到每个方法高达64K字节码指令的JVM限制.主要用例是高阶函数,它避免了创建实际lambda对象的成本,只是在一次立即发生的单个函数调用之后立即丢弃它.
每当你声明一个crossinline没有内联lambda时,内联本身就失去了它的目的.编译器警告你.
Q1:为什么(2)不编译但是(4)呢?
从他们的文件:
Inlinable lambdas只能在内联函数内部调用或作为无限参数传递...
回答:
该方法thread(...)不是一种inline方法,因此您将无法f作为参数传递.
Q2:noinline和crossinline有什么区别?
回答:
noinline将阻止lambdas的内联.当您有多个lambda参数并且只希望传递给内联函数的一些lambda内联时,这会很有用.
crossinline用于标记不允许非本地返回的lambda,特别是当这样的lambda传递给另一个执行上下文时.换句话说,你将无法return在这样的lambda中使用a .使用你的例子:
inline fun test(crossinline f: () -> Unit) {
thread { f() }
}
//another method in the class
fun foo() {
test{
//Error! return is not allowed here.
return
}
}
Run Code Online (Sandbox Code Playgroud)
问题3:如果(3)没有产生无性能改善,为什么(4)会这样做?
回答:
那是因为你在(3)中唯一的lambda已被标记,noinline这意味着你将有创建Function对象来承担你的lamda体的开销.对于(4),lambda仍然内联(性能改进),只是它不允许非本地返回.
| 归档时间: |
|
| 查看次数: |
7895 次 |
| 最近记录: |