切片或数组是否充当全局范围?
Do slices or arrays act as a global scope?
我对编程还是个新手。请原谅我缺乏计算机科学知识。不确定这个问题是特定于 Golang 还是一般的计算机科学...
我一直认为函数不会改变 variables/data 保持在它们自己的范围之外,除非你使用 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
不需要像 num 这样的 return 语句来修改 nums
会在 f1
内吗?
- 据说 Golang 函数传递值(而不是引用),
这不应该强制函数 return 份吗?[=29=]
- 这会发生在其他语言中吗? (我想我可能有
在其他语言中看到过这个)。
在go中,函数参数是按值传递的。这意味着,如果您传递一个 int(如 f1
),编译器将传递 f1
的值,本质上是复制它。如果函数采用 *int
而你传递 &num
,则编译器传递 &num
的值,它是指向 num
的指针。当函数改变*num
时,函数外变量的值也会改变。如果函数改变num
,num
的指针值也会改变,指向不同的变量
相比之下,Java 将所有原始值作为值传递,而所有 objects 通过引用传递。也就是说,如果您传递一个 int
,函数将无法修改调用者可见的那个 int 的值。如果你想传递一个 int 函数可以修改,你把它放在 class 中,然后在 Java.
中传递那个 class 的实例
一个切片(如 f2
)包含一个指向底层数组的指针。当您使用切片调用函数时,切片 header(包含指向底层数组的指针)被复制,因此当函数更改切片元素时,底层数组元素也会更改。
范围问题有些不同。函数的范围是它可以看到的所有变量。这些是全局变量(如果来自不同的包,导出的全局变量),函数参数,如果函数被声明为嵌套在另一个函数中,则所有变量在该函数中可见。
这是正确的行为,因为 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'。
"Why doesn't f2 require a return statement to modify nums like num would in f1?"
在 f2
中,您使用的是切片,它有一个指向原始数组的指针,因此 f2
可以更改外部数组。
"Golang functions are said to pass values (not reference), shouldn't that force to return copies? (If the question is related...)"
在f2
中切片本身是按值传递的,意思是指针和原始数组的长度和容量。
"Can this happen in other languages? (I think I may have seen this in other langues)"
范围太广,无法回答,有很多种语言,一般来说,如果您有一个指向外部世界数组的指针,是的。
编辑:
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
复制到 c
然后调用求和。
1 & 2) 在查看切片在 Go 中的工作方式时,这两个问题都可以得到回答。上面有a blog article。
一般情况下,Go中的所有变量都是按值传递的。您可以使用指针(例如 *int
表示 f1
)通过引用(或更正确的指针地址)传递。
但是,切片在技术上也是按值传递的。
当我们查看 here 时,我们可以了解它们的工作原理:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
Len
和Cap
是整数,但是Data
是指针。
复制此结构时(按值传递时),将制作 Len
、Cap
和 Data
的副本。由于 Data
是一个指针,因此对它指向的值所做的任何修改都将在您的函数 returns.
之后可见
你也可以
我对编程还是个新手。请原谅我缺乏计算机科学知识。不确定这个问题是特定于 Golang 还是一般的计算机科学...
我一直认为函数不会改变 variables/data 保持在它们自己的范围之外,除非你使用 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
不需要像 num 这样的 return 语句来修改 nums 会在f1
内吗? - 据说 Golang 函数传递值(而不是引用), 这不应该强制函数 return 份吗?[=29=]
- 这会发生在其他语言中吗? (我想我可能有 在其他语言中看到过这个)。
在go中,函数参数是按值传递的。这意味着,如果您传递一个 int(如 f1
),编译器将传递 f1
的值,本质上是复制它。如果函数采用 *int
而你传递 &num
,则编译器传递 &num
的值,它是指向 num
的指针。当函数改变*num
时,函数外变量的值也会改变。如果函数改变num
,num
的指针值也会改变,指向不同的变量
相比之下,Java 将所有原始值作为值传递,而所有 objects 通过引用传递。也就是说,如果您传递一个 int
,函数将无法修改调用者可见的那个 int 的值。如果你想传递一个 int 函数可以修改,你把它放在 class 中,然后在 Java.
一个切片(如 f2
)包含一个指向底层数组的指针。当您使用切片调用函数时,切片 header(包含指向底层数组的指针)被复制,因此当函数更改切片元素时,底层数组元素也会更改。
范围问题有些不同。函数的范围是它可以看到的所有变量。这些是全局变量(如果来自不同的包,导出的全局变量),函数参数,如果函数被声明为嵌套在另一个函数中,则所有变量在该函数中可见。
这是正确的行为,因为 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'。
"Why doesn't f2 require a return statement to modify nums like num would in f1?"
在 f2
中,您使用的是切片,它有一个指向原始数组的指针,因此 f2
可以更改外部数组。
"Golang functions are said to pass values (not reference), shouldn't that force to return copies? (If the question is related...)"
在f2
中切片本身是按值传递的,意思是指针和原始数组的长度和容量。
"Can this happen in other languages? (I think I may have seen this in other langues)"
范围太广,无法回答,有很多种语言,一般来说,如果您有一个指向外部世界数组的指针,是的。
编辑:
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
复制到 c
然后调用求和。
1 & 2) 在查看切片在 Go 中的工作方式时,这两个问题都可以得到回答。上面有a blog article。
一般情况下,Go中的所有变量都是按值传递的。您可以使用指针(例如 *int
表示 f1
)通过引用(或更正确的指针地址)传递。
但是,切片在技术上也是按值传递的。
当我们查看 here 时,我们可以了解它们的工作原理:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
Len
和Cap
是整数,但是Data
是指针。
复制此结构时(按值传递时),将制作 Len
、Cap
和 Data
的副本。由于 Data
是一个指针,因此对它指向的值所做的任何修改都将在您的函数 returns.
你也可以