请教一个 Golang Go语言中的函数问题
请教一个 Golang Go语言中的函数问题
代码片段如下
type St struct {
Val int
}
type f Func(s *St)
func Set(i int) f {
return func(s *St){
s.Val = i
}
}
func main(){
f := Set(100)
var ss St
f(&ss)
// ss.Val = 100 ???
}
最后我好奇的是,这个 100 是怎么设置进去的,同样的代码逻辑我用 c++ s.Val 的结果完全是个随机数
更多关于请教一个 Golang Go语言中的函数问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
不懂 C++,想问一下 C++有没有闭包的概念?
另外 Go 会自动初始化空值,比如 var ss St 之后,ss.Val 会自动初始化为 0,这里 C++ 是类似的规定吗?
更多关于请教一个 Golang Go语言中的函数问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
f 是个 function 啊
c++ 没有闭包。ss.Val 是 0 我能理解,但是不太理解为什么 ss.Val 是 100
贴代码可以用 markdown 语法,```
或者 gist
这样的代码太难看了
另外,可以把 C++ 是随机数的代码也贴出来对比一下
ss 的地址指到了 s
给你换种写法,就是个赋值而已<br>type St struct {<br> Val int<br>}<br><br>func f1(s *St, v int) {<br> s.Val = v<br>}<br><br>func TestA(t *testing.T) {<br> var ss St<br> f1(&ss, 100)<br><br> fmt.Println(ss.Val)<br>}<br>
就通过传值设置进去的啊,你的疑问点是在于闭包?
因为闭包保存的是你闭包环境,你的闭包环境下 i 是 100,所以你执行它的时候设置的就是 100
嗯,你这样写我能理解。其实我想问的是 100 这个值存到哪里去了。它为什么能正确设置
闭包
https://tour.golang.org/moretypes/25
经典闭包<br>package main<br><br>import "fmt"<br><br>func adder() func(int) int {<br> sum := 0<br> return func(x int) int {<br> sum += x<br> return sum<br> }<br>}<br><br>func main() {<br> pos, neg := adder(), adder()<br> for i := 0; i < 10; i++ {<br> fmt.Println(<br> pos(i),<br> neg(-2*i),<br> )<br> }<br>}<br><br>
c++ capture list ???
C++你把引用捕获改为赋值捕获就是 100 了
真是大神,佩服
Set(100) --> i = 100 --> f(&ss) --> s = &ss --> ss.Val = s.Val = i = 100
go 中关于闭包的一些实现过程可以看这个, [go 闭包的实现]( https://tiancaiamao.gitbooks.io/go-internals/content/zh/03.6.html)
同时,把你的代码复制到,https://godbolt.org/ , 选择 go 语言,再选择 386gc tip,对照汇编结果来理解。
正解
楼主 c++ lambda 引用了一个临时变量
谢谢,应该可以理解的更快一点了
c++要把对象的作用域 生命周期在脑子里想的很清楚
我感觉这是最难地方 比语法规则难多了
闭包,Set 执行完后返回的是一个函数,再执行把指针传进去,那肯定把 ss 的值给改了
两步都有复制。调用 Set 的时候,复制了 100 到一个地方存下来。调用 f 的时候,再把存下来的值复制给 s._i
在 lambda 表达式的内外,参数 i 的意义是不一样的。在表达式的内部:1. 引用捕获的时候,它是参数 i 的引用,调用 f 的时候,参数 i 已经没有了,所以最终得到的结果是随机的; 2. 赋值捕获的时候,它是参数 i 的复制
可能还是代码更直观点一点,Set 可以写成下面这样cpp<br>std::function<void(St*)> Set(int i) {<br> // 赋值捕获<br> return [j=i](St* s) {<br> s->Set(j);<br> };<br>// // 引用捕获<br>// return [&j=i](St* s) {<br>// s->Set(j);<br>// };<br>}<br>
嗯,我有点明白了,执行 Set 的时候把 i 复制到了 j,执行 f 的时候函数引用的就是捕获的值 j,也就是 i 的一个复制
Go 里的闭包函数在内存里是 code+data 形式表现的。
以你 Set 函数返回的 f 为例,在编译期就可以分析出它应该包含内部匿名函数的入口点地址和 i 的值,
在 x64 上就是 16 字节空间,也就是 main 栈上的 f 指向一个 16 字节的空间,执行 f=Set(100)的赋值后
第二个 8 字节就赋值为 100 。
执行 f(&ss)时参照 https://golang.org/s/go11func,在 x86_64 下 R0 用的是 DX 寄存器。
MOV …, R0
MOV 0(R0), R1 //R0+0=>R1,即函数入口地址
CALL R1 # called code can access “data” using R0,比如例子里的 100 就是 8(R0)
当然,很高兴帮助你解答关于Golang函数的问题。
在Go语言中,函数是代码的基本构建块,用于执行特定的任务。函数定义包括函数名、参数列表(可选)、返回类型(如果函数有返回值的话)以及函数体。
以下是一个简单的函数定义示例:
package main
import "fmt"
// 定义一个名为 add 的函数,接收两个整数参数并返回一个整数
func add(a int, b int) int {
return a + b
}
func main() {
// 调用 add 函数并打印结果
result := add(3, 4)
fmt.Println(result) // 输出: 7
}
在Go中,函数可以有多个返回值。例如:
func swap(x, y string) (string, string) {
return y, x
}
在调用函数时,可以使用命名返回值来提前设置返回值,并在函数体中修改它们:
func modifyValues() (a, b int) {
a = 1
b = 2
a, b = b, a + b
return
}
此外,Go还支持匿名函数和闭包,它们可以在需要的地方定义并使用,非常适合在回调函数和迭代器等场景中使用。
如果你有具体的函数问题或代码示例,请提供详细信息,这样我可以给出更具体的帮助和建议。