go基础第四篇:常见开发错误

1、入参数组修改不了

一个无返回值的函数,入参是一个基本数据类型的数组,在函数中修改数组的值,是不会生效的。想要生效,需要把入参由数组改为数组指针或者slice。

如果数组的元素不是基本数据类型,而是自定义的struct类型,那么除了把入参由数组改为数组指针或者slice外,把入参由普通数组改成指针数组也行。

func f(s [5]int) {
	for i := range s {
		s[i] = 10
	}
}

func main() {
	s := [5]int{1, 2, 3, 4, 5}
	fmt.Println(s)
	f(s)
	fmt.Println(s)
}

上例中,第二次打印s依旧会打印出[1 2 3 4 5]。

把入参由基本类型数组改为基本类型数组的指针,对数组的改动会生效:

func f(s *[5]int) {
	for i := range s {
		s[i] = 10
	}
}

func main() {
	s := [5]int{1, 2, 3, 4, 5}
	fmt.Println(s)
	f(&s)
	fmt.Println(s)
}

上例中,第二次打印s会打印出[10 10 10 10 10]。

把入参由基本类型数组改为基本类型切片,对切片的改动也会生效:

func f(s []int) {
	for i := range s {
		s[i] = 10
	}
}

func main() {
	s := []int{1, 2, 3, 4, 5}
	fmt.Println(s)
	f(s)
	fmt.Println(s)
}

上例中,第二次打印s会打印出[10 10 10 10 10]。

即使数组的元素是自定义的struct类型,对数组的改动也不会生效:

type Person struct {
	Name string
	Age  int
}

func f(s [2]Person) {
	for i := range s {
		s[i].Age = 30
	}
}

func main() {
	p1 := Person{Name: "John", Age: 18}
	p2 := Person{Name: "Jane", Age: 25}
	s := [2]Person{p1, p2}
	fmt.Println(s)
	f(s)
	fmt.Println(s)
}

上例中,第二次打印s依旧会打印出[{John 18} {Jane 25}]。

把入参由普通数组改成指针数组,对数组的改动会生效:

type Person struct {
	Name string
	Age  int
}

func f(s [2]*Person) {
	for i := range s {
		s[i].Age = 30
	}
}

func main() {
	p1 := &Person{Name: "John", Age: 18}
	p2 := &Person{Name: "Jane", Age: 25}
	s := [2]*Person{p1, p2}
	fmt.Println(s)
	f(s)
	for _, e := range s {
		fmt.Println(e)
	}
}

2、入参slice append不了

一个无返回值的函数,入参是一个slice,在函数中调用append函数给slice添加数据。函数执行完后,打印该slice,发现slice并没有变化,不管slice的元素类型是指针类型还是非指针类型,都不行。想要生效,需要把入参由slice改为slice指针。

函数入参是slice,在函数中append不生效:

type Person struct {
	Name string
	Age  int
}

func f(s []Person) {
	s = append(s, Person{"Molly", 20})
}

func main() {
	p1 := Person{Name: "John", Age: 18}
	p2 := Person{Name: "Jane", Age: 25}
	s := []Person{p1, p2}
	fmt.Println(s)
	f(s)
	fmt.Println(s)
}

上例中,第二次打印s依旧会打印出[{John 18} {Jane 25}]。

把入参由slice改为slice指针,会发现有变化:

type Person struct {
    Name string
    Age  int
}

func f(s *[]Person) {
    *s = append(*s, Person{"Molly", 20})
}

func main() {
    p1 := Person{Name: "John", Age: 18}
    p2 := Person{Name: "Jane", Age: 25}
    s := []Person{p1, p2}
    fmt.Println(s)
    f(&s)
    fmt.Println(s)
}

上例中,第二次打印s会打印出[{John 18} {Jane 25} {Molly 20}]。 

3、在函数中修改struct slice中元素的属性不生效

type Person struct {
	Name string
	Age  int
}

func f(s []Person) {
	for _, e := range s {
		e.Age = 30
	}
}

func main() {
	p1 := Person{Name: "John", Age: 18}
	p2 := Person{Name: "Jane", Age: 25}
	s := []Person{p1, p2}
	fmt.Println(s)
	f(s)
	fmt.Println(s)
}

修复方案有三种:

第一种:把修改struct slice元素属性的函数改为用range表达式的索引取元素,而不是直接从range表达式取元素,如下:

func f(s []Person) {
	for i := range s {
		s[i].Age = 30
	}
}

第二种:把修改struct slice元素属性的函数改为用for i := 0; i < len(s); i++,进而通过索引取元素,如下:

func f(s []Person) {
    for i := 0; i < len(s); i++ {
        s[i].Age = 30
    }
}

第三种:把struct slice改为struct指针数组,如下:

type Person struct {
	Name string
	Age  int
}

func f(s []*Person) {
	for _, e := range s {
		e.Age = 30
	}
}

func main() {
	p1 := &Person{Name: "John", Age: 18}
	p2 := &Person{Name: "Jane", Age: 25}
	s := []*Person{p1, p2}
	fmt.Println(s[0])
	f(s)
	fmt.Println(s[0])
}

由于自己之前不知道前两种方案,所以在项目中用的是第三种方案。

posted on 2021-07-06 10:21  koushr  阅读(69)  评论(0)    收藏  举报

导航