1. ホーム
  2. スクリプト・コラム
  3. ゴラン

Goのアドレッサブルとノンアドレッサブルを1つの記事で理解する

2022-02-14 17:17:17

1.アドレサブルとはどういう意味ですか?

演算子 & を使って直接アドレス指定できるオブジェクトは、アドレス指定可能です ( Addressable ). 例えば、次のような例です。

func main() { 
    name := "iswbm" 
    fmt.Println(&name)  
    // output: 0xc000010200 
} 



プログラムはエラーなく実行され、次のように表示されます。 name 変数がアドレス指定可能であることを示します。

でも、"はダメなんです。 iswbm "この文字列はアドレス指定可能です。

" iswbm "は文字列であり、文字列は後述するように不変でアドレス指定ができない。

ひとつひとつ見ていく前に、まず結論から言うと

  • ポインターは、&Profile{}に対応することができます。
  • 変数がアドレス指定可能: name := Profile{}.
  • リテラルな数量は全くアドレス指定できない。プロファイル{}

2. アドレサブルとは?

変数: &x

func main() { 
    name := "iswbm" 
    fmt.Println(&name)  
    // output: 0xc000010200 
} 



ポインタ: &*x

type Profile struct { 
    Name string 
name string } 
 
func main() { 
    fmt.Println(unsafe.Pointer(&Profile{Name: "iswbm"})) 
    // output: 0xc000108040 
} 



配列要素のインデックス:&a[0]。

func main() { 
    s := [...] int{1,2,3} 
    fmt.Println(&s[0]) 
    // output: xc0000b4010 
} 



スライス

func main() { 
    fmt.Println([]int{1, 2, 3}[1:]) 
} 



スライス要素インデックス:&s[1]。

func main() { 
    s := make([]int , 2, 2) 
    fmt.Println(&s[0])  
    // output: xc0000b4010 
} 



結合リテラル: &struct{X type}{value}。

すべての組合せリテラルは、次のようにアドレス指定不可です。

type Profile struct { 
    Name string 
name string } 
 
func new() Profile { 
    return Profile{Name: "iswbm"} 
} 
 
func main() { 
    fmt.Println(&new()) 
    // cannot take the address of new() 
} 




上の書き出しとこの書き出しの違いに注意してください。この書き出しは、&がアドレスを取る操作ではなく、構造体をインスタンス化するポインタを表すという、異なる意味を持ちます。

type Profile struct { 
    Name string 
name string } 
 
func main() { 
    fmt.Println(&Profile{Name: "iswbm"}) // ok 
} 




結合されたリテラルはアドレス指定できませんが、結合されたリテラルのフィールド属性をアドレス指定(直接アクセス)することは可能です。

type Profile struct { 
    Name string 
name string } 
 
func new() Profile { 
    return Profile{Name: "iswbm"} 
} 
 
func main() { 
    fmt.Println(new().Name) 
} 



3. アドレス指定できないものは何ですか?

定数

import "fmt" 
 
const VERSION = "1.0" 
 
func main() { 
    fmt.Println(&VERSION) 
} 



文字列

func getStr() string { 
    return "iswbm" 
} 
func main() { 
    fmt.Println(&getStr()) 
    // cannot take the address of getStr() 
} 



機能またはメソッド

func getStr() string { 
    return "iswbm" 
} 
func main() { 
    fmt.Println(&getStr) 
    // cannot take the address of getStr 
} 



基本的なタイプ・リテラル

リテラル量はに分けられる。 基本型リテラルと複合型リテラル。

値のテキスト表現である基本型リテラルは、想定外であり、対処できない。

func getInt() int { 
    return 1024 
} 
 
func main() { 
    fmt.Println(&getInt()) 
    // cannot take the address of getInt() 
} 



マップ内の要素

辞書は特殊であり、2つの視点から逆算して導き出すことができる。辞書の要素がアドレス指定可能な場合、どうなるのだろうか。

辞書の要素が存在しない場合、ゼロ値を返します。ゼロ値は不変のオブジェクトなので、アドレス指定可能であれば大きな問題になります。

また、辞書の要素が存在する場合、仮にGo map の実装では、要素のアドレスは可変であるため、アドレス指定した結果も意味がないことになります。

この2点から、Mapの要素はアドレス指定できないのが常識です。

func main() { 
    p := map[string]string { 
        "name": "iswbm", 
    } 
 
    fmt.Println(&p["name"]) 
    // cannot take the address of p["name"] 
} 



これを理解すれば、次のコードがなぜエラーを報告しているのか理解できるはずです。

package main 
 
import "fmt" 
 
type Person struct { 
    Name string 
    Email string 
} 
 
func main() { 
    m := map[int]Person{ 
        1:Person{"Andy", "[email protected]"}, 
        2:Person{"Tiny", "[email protected]"}, 
        3:Person{"Jack", "[email protected]"}, 3:Person{"Jack", "[email protected]"}, 
    } 
 
    //compile error: cannot assign to struct field m[1].Name in map 
    m[1].Name = "Scrapup" 



配列リテラル

配列リテラルはアドレス指定できないので、配列リテラルをスライスするときは、実際には内部要素のアドレスを探していることになります。

func main() { 
    fmt.Println([3]int{1, 2, 3}[1:]) 
    // invalid operation [3]int literal[1:] (slice of unaddressable value) 
} 



以上で、Goのアドレス指定可能・不可能についての記事を終了します。Goのアドレス指定可能、アドレス指定不可能については、Script Houseの過去の記事を検索するか、引き続き以下の関連記事を参照してください。