go - 切片或数组是否充当全局范围?
问题描述
我还是编程新手。原谅我缺乏计算机科学知识。不确定这个问题是否特定于 Golang 或一般的计算机科学......
我一直认为函数不会改变它们自己范围之外的变量/数据,除非您使用 return 语句回到另一个范围,或者除非它们在范围层次结构中更高。有人可能会争辩说,函数f1
和f2
在这个例子中是从较低的范围调用的。但是,这仍然不能解释为什么我得到不同的结果变量num
和nums
。
package main
import "fmt"
func f1(a int) {
a = 50 // this will not work, as it shouldn't
}
func f2(a ...int) {
a[0] = 50 // this will work without return statement
a[1] = 50 // this will work without return statement
}
func main() {
num := 2
nums := []int{2, 2}
f1(num)
f2(nums...)
fmt.Printf("function f1 doesn't affect the variable num and stays: %v\n", num)
fmt.Printf("function f2 affects the variable nums and results in: %v", nums)
问题:
- 为什么
f2
不需要 return 语句来修改像 num 内的 numf1
? - 据说 Golang 函数传递值(而不是引用),这不应该强制函数返回副本吗?
- 这可以在其他语言中发生吗?(我想我可能已经在其他语言中看到过这个)。
解决方案
这是正确的行为,因为a ...int
等于切片,例如:a []int
func f2(a []int) {
a[0] = 50
a[1] = 50
}
func main() {
b := []int{2, 2}
f2(b)
fmt.Println(b) // [50 50]
}
切片是原始数据的视图,此处为“b”。
“为什么 f2 不需要像 f1 中的 num 那样修改 nums 的 return 语句?”
在f2
您使用切片时,它有一个指向原始数组的指针,因此f2
可以更改外部数组。
“据说Golang函数传递值(而不是引用),那不应该强制返回副本吗?(如果问题是相关的......)”
在f2
slice 本身是按值传递的,意思是指针和原始数组的长度和容量。
“这会发生在其他语言中吗?(我想我可能在其他语言中看到过)”
回答太宽泛了,有很多语言,一般来说,如果你有一个指向外部世界数组的指针,是的。
编辑:
package main
import "fmt"
func sum(a ...int) int {
s := 0
for _, v := range a {
s += v
}
return s
}
func f2(a []int) {
c := make([]int, len(a))
copy(c, a)
c[0] = 50
fmt.Println(sum(c...)) // 52
}
func main() {
b := []int{2, 2}
fmt.Println(sum(1, 2, 3, 4)) // 10
fmt.Println(sum(b...)) // 4
f2(b)
fmt.Println(b) // [2 2]
}
注意:上面
的sum()
函数是一个纯函数,因为它没有副作用。
上面的新f2
函数是一个纯函数,因为它没有副作用:它复制a
intoc
然后调用 sum。
推荐阅读
- python - 将 numpy 数组从 @njit 函数传递给 C 函数
- c++ - SDL2 能否一次渲染两个不同的窗口,每个窗口都有自己的 SDL_Window 和 SDL_Renderer?
- javascript - 如果第一个表的至少一个复选框未选中,则无法使用 JavaScript 选中第二个表的任何复选框
- python-3.x - Python:识别涉及哪个 excel 单元格
- javascript - TypeError:无法读取未定义的属性“跟随”
- exception - 在 .Net Core MVC 中使用 Hellang 中间件进行异常处理
- onelogin - SCIM OneLogin 角色变量
- mysql - MySQL查询以查找在两列中具有相同值但在第三列中具有不同值的行
- c# - 试图在外键上加入表,但输出不正确。CRUD 也没有完全工作
- c# - 改变方向但不影响力