首页 > 解决方案 > 切片或数组是否充当全局范围?

问题描述

我还是编程新手。原谅我缺乏计算机科学知识。不确定这个问题是否特定于 Golang 或一般的计算机科学......

我一直认为函数不会改变它们自己范围之外的变量/数据,除非您使用 return 语句回到另一个范围,或者除非它们在范围层次结构中更高。有人可能会争辩说,函数f1f2在这个例子中是从较低的范围调用的。但是,这仍然不能解释为什么我得到不同的结果变量numnums

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)

问题:

  1. 为什么f2不需要 return 语句来修改像 num 内的 num f1
  2. 据说 Golang 函数传递值(而不是引用),这不应该强制函数返回副本吗?
  3. 这可以在其他语言中发生吗?(我想我可能已经在其他语言中看到过这个)。

标签: gocomputer-science

解决方案


这是正确的行为,因为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函数传递值(而不是引用),那不应该强制返回副本吗?(如果问题是相关的......)”

f2slice 本身是按值传递的,意思是指针和原始数组的长度和容量。

“这会发生在其他语言中吗?(我想我可能在其他语言中看到过)”

回答太宽泛了,有很多语言,一般来说,如果你有一个指向外部世界数组的指针,是的。


编辑:

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函数是一个纯函数,因为它没有副作用:它复制aintoc然后调用 sum。


推荐阅读