fn func(){
let mut a = 0;
for i in 1..=10{
a = (|x| a+x)(i); // 这个匿名函数 |x| a+x 是否会重复的声明10次并调用?
}
}
fn func(){
let mut a = 0;
for i in 1..=10{
fn fun() -> i32 {return 100;} // 这个局域的函数会否声明10次?
a += fun();
}
}
A closure expression produces a closure value with a unique, anonymous type that cannot be written out. A closure type is approximately equivalent to a struct which contains the captured variables. For instance, the following closure:
1
共 4 条评论, 1 页
评论区
写评论是的,不内联也会把context找个内存块存着,每次循环都只会访问这一块。另外贴主这个例子连内存块也不需要,不捕获外部变量的匿名函数在Rust里等价于函数(函数指针)的,编译之后就算不内联也是直接一个call,也不会占额外内存。
👇
johnmave126: 就算不内联也不会
仔细想想,如果循环长度是一个变量,假设每一次都需要一个新的内存段用来储存匿名函数,编译期是无法知道需要多少个匿名函数的。难道程序还能JIT现场在内存里编译匿名函数?
事实上,编译器是block level的,会先计算出一个CFG(control flow graph),匿名函数是一个block,不会被复制很多份。
对于第一个情况换个问题就是,在不考虑优化的情况下,运行期这样是否会产生多个闭包实例(本质上是context+函数地址),答案是会的。
对于第二个情况,运行期也不会,因为fn定义的位置只影响可见性,编译时会被提升到外层,函数调用就是普通的函数调用。
就算不内联也不会
仔细想想,如果循环长度是一个变量,假设每一次都需要一个新的内存段用来储存匿名函数,编译期是无法知道需要多少个匿名函数的。难道程序还能JIT现场在内存里编译匿名函数?
事实上,编译器是block level的,会先计算出一个CFG(control flow graph),匿名函数是一个block,不会被复制很多份。
对于第一个情况换个问题就是,在不考虑优化的情况下,运行期这样是否会产生多个闭包实例(本质上是context+函数地址),答案是会的。
对于第二个情况,运行期也不会,因为fn定义的位置只影响可见性,编译时会被提升到外层,函数调用就是普通的函数调用。
不会,没必要,你这里的匿名函数都没有捕获外部变量,就等于一个普通的函数,相当于直接调用函数。 甚至你这个函数太短了,完全可以内联掉,在开了优化之后估计连函数调用都没了。 直接等价于:
另外加上你这里都是常数,真正开优化其实应该优化成这一句话:
在godbolt上看了一下,不会