在看了文章Go 语言的优点,缺点和令人厌恶的设计之后,受益匪浅,觉得需要总结联系一下强化一下记忆。
struct可以通过赋值语句来复制,如下:
虽然y是复制的x,但是修改y内array内容时候,会把x的也改变了。
import "fmt"
func main() {
x := TestFo{Name: "foo1", Childs: []string{"foo1-2"}}
y := x
y.Name = "boo1"
y.Childs[0] = "boo1-2"
fmt.Printf("x is %v\n", x) //x is {foo1 [boo1-2]}
fmt.Printf("y is %v\n", y) //y is {boo1 [boo1-2]}
}
type TestFo struct {
Name string
Childs []string
}
这个例子就很清晰的描述了为什么会发上上面的情况,slice,map,array都是指针,复制struct时候,如果是指针只会复制指针,不会复制指针指向的值,可以看到,打印出来的两个指针是相同的,所以复制后的struct修改指针指向的值会影响被复制的struct。
func main() {
x := TestFo{Name: "foo1", Child: &Child{Name: "foo1-2"}, Child2: Child{Name: "foo1-3"}}
y := x
y.Name = "boo1"
y.Child.Name = "boo1-2"
y.Child2.Name = "boo1-3"
fmt.Printf("x is %v x.Child is %v\n", x, x.Child) // x is {boo1 0xc42007a1b0 {foo1-3}} y.Child is &{boo1-2}
fmt.Printf("y is %v y.Child is %v\n", y, y.Child) // y is {boo1 0xc42007a1b0 {boo1-3}} y.Child is &{boo1-2}
}
type TestFo struct {
Name string
Child *Child
Child2 Child
}
type Child struct {
Name string
}
package main
type Car struct {
Name string
}
func (c Car) Print() {
println("this is "+c.Name)
}
type City struct {
Car
}
func main() {
c := City{}
c.Name = "bmw"
c.Print()
}
package main
type Car struct {
Name string
}
type People struct {
Name string
}
type City struct {
Car
People
}
func main() {
c := City{}
// c.Name = "car" // 报错:ambiguous selector c.Name
c.Car.Name = "car"
c.People.Name = "people"
}
package main
type Car struct {
Name string
}
type Build struct {
BuildName string
}
type City struct {
Build
*Car
}
func main() {
c := City{}
// c.Name = "car" // 编译是可以通过的,但是运行时会在这里中断:bad
println(fmt.Sprintln(c)) // {{}, } 这里面 {}是struct的初值,是指针类型的初值。
c.Car = &Car{}
c.Name = "car"
c.BuildName = "big wall"
}
对于[:]或[x:]这种切片进行append操作之后,修改切片内的值,要小心,如果原数组的cap(array) > len(array),而你append之后的长度有小于等于原数组的cap,那修改切片会影响到原数组,否则不会。
原因在于,array2 = append(array1, …)操作如果cap(array1) < len(array2),那么append会重新分配内存用以拼接,那array2的地址就是新地址,修改array2不会影响到array1,如果cap(array1) >= len(array2),那么array2的地址是包含在array1里的,修改array2[:len(array1)-1]的值,会影响到array1。具体例子如下:
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := s1[3:]
s3 := append(s1[3:], 6)
s3[0] = 7
fmt.Printf("s1=%v s2=%v s3=%v\n", s1, s2, s3) // s1=[1 2 3 4 5] s2=[4 5] s3=[7 5 6]
ss1 := make([]int, 5, 10)
for i := 1; i < 6; i++ {
ss1[i-1] = i
}
ss2 := ss1[3:]
ss3 := append(ss2, 6)
ss3[0] = 7
fmt.Printf("ss1=%v ss2=%v ss3=%v\n", ss1, ss2, ss3) // ss1=[1 2 3 7 5] ss2=[7 5] ss3=[7 5 6] ss1[3]和ss2[0]被改变了!
}
package main
import "fmt"
func main() {
var t *Test
var f Foo = t
if f != nil {
println(t, f) // 0x0 (0x114f580,0x0)
fmt.Printf("%v %v\n", t, f) //
f.Can() // Test Can
f.Cannot() // panic: value method main.Test.Cannot called using nil *Test pointer
}
}
type Foo interface {
Can()
Cannot()
}
type Test struct{}
func (*Test) Can() { fmt.Println("Test Can") }
func (Test) Cannot() { fmt.Println("Test Cannot") }