Golandの値と参照タイプ


Golandの値と参照タイプ
新しいプロジェクトで使用されるGoland.以前はPythonでプロジェクトをしていましたが、Pythonの基本変数の付与値は参照リダイレクトです.Golandは少し違いますが、ここでテストをして変数値、アドレスを直接印刷して変数のコピー状況を確認します.
package main
import "fmt"

func getInt() int {
	i := 5
	println("in getInt, i", i, &i)
	return i
}

func intTest(i int) {
	println("in intTest, i", i, &i)
	i = 99
}

func listTest(list []int) {
	println("in listTest, list", &list, list)
	list[0] = 99
}

func mapTest(mapInt map[int]int) {
	println("in mapTest, mapInt", mapInt, &mapInt)
	mapInt[99] = 100
}

func main() {
	t := 1
	fmt.Println("in main, t", t, &t)
	t = 2
	fmt.Println("in main, t", t, &t)
	t = getInt()
	fmt.Println("in main, t", t, &t)
	intTest(t)
	fmt.Println("in main, t", t, &t)

	fmt.Println("*************************")
	l := []int{1,2,3}
	println("in main, l", &l, l)
	l = []int{1,2,3,4,5}
	println("in main, l", &l, l)

	l2 := l
	println("in main, l2", &l2, l2)
	listTest(l)
	fmt.Println("in main, l", l)

	fmt.Println("*************************")
	mapInt := make(map[int]int)
	mapInt[1] = 2
	println("in main, mapInt", mapInt, &mapInt)
	mapTest(mapInt)
	println("in main, mapInt", mapInt, &mapInt)
	fmt.Println("in main, mapInt", mapInt)
}

    
in main, t 1 0xc0000140a0
in main, t 2 0xc0000140a0
in getInt, i 5 0xc00006ade0
in main, t 5 0xc0000140a0
in intTest, i 5 0xc00006ade8
in main, t 5 0xc0000140a0
*************************
in main, l 0xc00006ae58 [3/3]0xc000012140
in main, l 0xc00006ae58 [5/5]0xc00001a060
in main, l2 0xc00006ae40 [5/5]0xc00001a060
in listTest, list 0xc00006ae28 [5/5]0xc00001a060
in main, l [99 2 3 4 5]
*************************
in main, mapInt 0xc00006adf0 0xc000062180
in mapTest, mapInt 0xc00006adf8 0xc000062180
in main, mapInt 0xc00006adf0 0xc000062180
in main, mapInt map[1:2 99:100]

ぶんせき
まず、第1のグループの結果を見て、簡単なint変数tを2に再割り当てた後、メモリ内のアドレスは変わらない.Pythonとは異なり、Python単純オブジェクト付与は参照リダイレクトであり、新しいオブジェクトを参照するとid(obj)の結果が変更されます.Golandは、元のオブジェクトに基づいて修正し、元のオブジェクトの内容を変更します.関数のパラメータ、戻り値は新しいオブジェクトをコピーし、コピーしたオブジェクトを変更しても元のオブジェクトには影響しません.
第2のグループの結果を見ると、スライスタイプlは、印刷の最初の数値が変数アドレスであり、後に[len/cap]配列メモリアドレスが接続され、スライスは配列メモリアドレスへの参照を保持している.2回目はスライスに値を割り当て,同じオブジェクトアドレスは変わらずlen,cap,配列アドレスが変化する.関数listTestでは、パラメータは同じように新しいオブジェクトを生成し、スライスコピーオブジェクトのlen、cap、配列メモリアドレスはメタオブジェクトと一致し、コピースライス中の要素を変更すると、同じ連続配列メモリを参照するため、元のオブジェクトにも反映され、最後にmain中のl[0]=99
第3のグループの結果を見ると、mapタイプでは、印刷の最初の値はmap変数のアドレスであり、第2のパラメータはmapオブジェクトが参照するデータブロックアドレスである.同様にmapオブジェクトはパラメータとしてlistと同様に新しいオブジェクトがコピーされ、古いオブジェクトが参照するブロックアドレスが一致し、コピーオブジェクトのブロック内のデータが変更され、古いオブジェクトのデータに影響します.
まとめ
  • Golandは存在するオブジェクトに値を再割り当て、元のオブジェクトメモリのデータを変更し、Python参照リダイレクトとは異なる
  • を参照する.
  • Golandではslices、map、channelが参照タイプであり、残りの単純タイプは値タイプであり、値タイプオブジェクトにはオブジェクトに必要なすべての内容が空間に含まれており、参照タイプは基本情報のほかに共有可能なデータブロック
  • を参照している.
  • Golandオブジェクトは、関数パラメータ、関数戻り値、オブジェクト間付与値、copyなどのメカニズムとして古いオブジェクトから新しいオブジェクトをコピーします.ここでは、浅いコピーメカニズム、値タイプの完全なコピー、共通参照データブロック、参照アドレスのコピーです.
  • コピーオブジェクトを変更する場合、コピーオブジェクトは参照タイプであり、参照データブロック内のデータを変更すると、そのデータブロックを参照するすべての参照オブジェクトに影響し、バグが発生しやすい.
  • 深いコピーは、シーケンス化、逆シーケンス化を考慮して実現することができ、深いコピーは時間がかかり、
  • を推奨する必要はありません.