GO——值方法與指針方法的區別

指針方法

特點

指針方法複製源值的指針並以指針參數的形式傳入函數中,函數中對指針參數內容的修改即爲源值內容的修改,所以會全部反應到源值上。
可對照 輸出:1 2 4 佐證。

值方法

特點

值方法會創建新變量以複製源值內容,並將該新變量以值參數的形式傳入函數中, 所以函數中值參數是源值內容的複製,與源值再無聯繫,所以函數內值參數內容的修改不會反應到源值上。
可對照 輸出:1 3 4 佐證。

特例

值方法對引用類型1源值的修改,會在源值上反應。
可對照 輸出:6 7 8 deskmate[0] addr 佐證。

原理

切片類型指向底層數組,是對底層匿名數組的引用。
調用值方法時複製了原址內容的的值參數指向的仍是與源值相同的底層數組,
若不觸發底層數組的擴容,則對值參數的所有修改都會反應到源值上。
當對值參數的改動觸發底層數組擴容時,值參數指向擴容後的新數組,源值指向舊數組。
只有此時值參數和源值才真正獨立互不影響。

代碼

源碼
package main

import "fmt"

type Student struct {
	Age      int
	Name     string
	DeskMate []string
}

func (s *Student) SetAge(age int) {
	s.Age = age
	fmt.Printf("2 func SetAge:: addr: %p type: %T data: %+v \n", s, s, *s)
}

func (s Student) SetName(name string) {
	s.Name = name
	fmt.Printf("3 func SetName::  addr: %p %T data: %+v \n", &s, s, s)
}

func (s Student) ModifyDeskMate(deskMate string) {
	s.DeskMate[0] = deskMate
	fmt.Printf(
		"7 func ModifyDeskMate:: deskmate addr: %p deskmate[0] addr: %p  deskmate[0] data: %+v \n",
		&s.DeskMate, &s.DeskMate[0], s.DeskMate[0])
}

func main() {

	var s Student

	fmt.Printf("1 func main:: addr: %p type: %T data: %+v \n", &s, s, s)

	(&s).SetAge(12)   // 完全等價於s.SetAge(12), 因爲變量調用值方法/指針方法時, go內部會自動幫我們把變量轉換爲合適的類型
	s.SetName("anne") // 完全等價於(&s).SetName("anne")

	fmt.Printf("4 func main:: addr: %p type: %T data: %+v \n", &s, s, s)

	fmt.Println("----------------------special case----------------------")

	s.DeskMate = []string{"barry", "charles"}

	fmt.Printf("5 func main:: addr: %p type: %T data: %+v \n", &s, s, s)
	fmt.Printf(
		"6 func main:: deskmate addr: %p deskmate[0] addr: %p  deskmate[0] data: %+v \n",
		&s.DeskMate, &s.DeskMate[0], s.DeskMate[0])

	s.ModifyDeskMate("anduin")

	fmt.Printf(
		"8 func main:: deskmate addr: %p deskmate[0] addr: %p  deskmate[0] data: %+v \n",
		&s.DeskMate, &s.DeskMate[0], s.DeskMate[0])

	fmt.Printf("9 func main:: addr: %p type: %T data: %+v \n", &s, s, s)
}

輸出
1 func main:: addr: 0xc000060150 type: main.Student data: {Age:0 Name: DeskMate:[]} 
2 func SetAge:: addr: 0xc000060150 type: *main.Student data: {Age:12 Name: DeskMate:[]} 
3 func SetName::  addr: 0xc000060210 main.Student data: {Age:12 Name:anne DeskMate:[]} 
4 func main:: addr: 0xc000060150 type: main.Student data: {Age:12 Name: DeskMate:[]} 
----------------------special case----------------------
5 func main:: addr: 0xc000060150 type: main.Student data: {Age:12 Name: DeskMate:[barry charles]} 
6 func main:: deskmate addr: 0xc000060168 deskmate[0] addr: 0xc00000c080  deskmate[0] data: barry 
7 func ModifyDeskMate:: deskmate addr: 0xc000060378 deskmate[0] addr: 0xc00000c080  deskmate[0] data: anduin 
8 func main:: deskmate addr: 0xc000060168 deskmate[0] addr: 0xc00000c080  deskmate[0] data: anduin 
9 func main:: addr: 0xc000060150 type: main.Student data: {Age:12 Name: DeskMate:[anduin charles]} 

  1. 常見引用類型: slice, map, channel
    常見值類型: int, float, bool, string, array ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章