0
0

More than 3 years have passed since last update.

A Tour of Go メモ 【3】1日目

Last updated at Posted at 2020-09-13

 ポインタ、 構造体、 配列、 スライス

A Tour of Go

ポインタ

Golangのポインタ渡し初心者を卒業した

func main() {
    i, j ;= 10, 200

    # pはiの値を参照する 
    p := &i 

    # iとpのアドレスを取得する
    fmt.Println(&i)
    fmt.Println(&p)

   # pが参照している変数、つまり、iを表示する
    fmt.Println(*p)

    # pが参照する変数に21を代入する。つまり、i に 21 を代入する
    *p = 21
    fmt.Println(i)

    # pはjの値を参照する
    p = &j

    # pが参照する値に”pが参照する値を100で割った値”を代入する。
    # つまり、jに"jを100で割った値"を代入する
    *p = *p / 100
    fmt.Println(j)
   
}
// iを参照したpの値
>10 
// *pに21を代入した後のi
>21
// iのアドレス
>0xc000100010
// pのアドレス iを参照して値は同じだが、アドレスは違う
>0xc000102018 
>2

構造体

struct(構造体)はフィールド(field) の集まり

type Vertex struct {
  X int
  Y int
}

func main() {
   fmt.Println(Vertex{1, 2})
   v := Vertex{1, 2}
   fmt.Println(v.X)
   v.X = 4
   fmt.Println(v.X)

}

> {1, 2}
> 1
> 4

構造体とポインタ

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
      fmt.Println(v)
        # pはv(Vertex)を参照する
    p := &v

        # pが参照しているVertexのXに値を代入する
    p.X = 1e9
    fmt.Println(v)
}
> {1 2}
// ポインタを通して、Xの値が再代入されている
> {1000000000 2}

Struct リテラル

type Vertex struct {
    X, Y int
}

var (
        v1 = Vertex{1, 2} 

        # Xには1を、Yは0(何も代入されていないので、初期値の0になる)
        v2 = Vertex{X: 1} 

        # X にも Y にも何も代入されていないので、初期値の0になる
        v3 = Vertex{}

        # ちょっとよくわからない・・・
        p  = &Vertex{1, 2}

)

func main() {
    fmt.Println(v1, p, v2, v3)
}

> {1 2} &{11 2} {1 0} {0 0}

配列

拡張不可なので、append関数で要素を追加できない

func main() {
       var a [2]string
       a[0] = "Hello"
       a[1] = "World"
       fmt.Println(a[0], a[1])
       fmt.Println(a)

       primes := [6]int{1,2,3,4,5,6}
       fmt.Println(primes)
}

> Hello World
> [Hello World]
> [2 3 5 7 11 13]

スライス

append関数で要素の追加が可能、つまり、拡張可能
```
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13}

    var s []int = primes[1:4]
    fmt.Println(s)
    fmt.Println(primes[:1])
    fmt.Println(primes[2:])

}

[3 5 7]
[2 3 ]
[5 7 11 13]

  • スライスした後の配列に値を代入すると元の配列が変わる

func main() {
names := [4]string{
"John",
"Paul",
"George",
"Ringo",
}
fmt.Println(names)

a := names[0:2]
b := names[1:3]
fmt.Println(a, b)

b[0] = "XXX"
fmt.Println(a, b)
fmt.Println(names)
fmt.Println(names)

}

[John Paul George Ringo]
[John Paul] [Paul George]
[John XXX] [XXX George]
[John XXX George Ringo]
//元の配列が変わっている
[John XXX George Ringo]
```

スライス リテラル

func main() {
    q := []int{2, 3, 4, 5, 7, 11, 13}
    fmt.Println(q)

    r := []bool{true, false, true, true, false, true}
    fmt.Println(r)

    s := []struct{
        i int
        b bool
    }{
       {2, true}
       {3, false},
       {5, true},
       {7, true},
       {11, false},
       {13, true}
    }
    fmt.Println(s)
}
> [2 3 5 7 11 13]
> [true false true true false true]
> [{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]

 スライスのlengthとcapacity

length ・・・ 実際に配列に入っている要素の数
capacity ・・・ 確保されているメモリの領域
*配列とスライスは全くの別物
Go言語のスライスで勘違いしやすいこところ

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s)

    // Slice the slice to give it zero length.
    s = s[:5]
    printSlice(s)

    // Extend its length.
    s = s[:6]
    printSlice(s)

    // Drop its first two values.
    s = s[2:]
    printSlice(s)

    s = s[:5]
    printSlice(s)

    s = append(s, 4)
    printSlice(s)
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

> len=6 cap=6 [2 3 5 7 11 13]

//要素を一つ削る、しかし、capacityは減っていない
> len=5 cap=6 [2 3 5 7 11]

//長さを戻すと削ったはずの要素が復活する
> len=6 cap=6 [2 3 5 7 11 13]

// ドロップするとlengthもcapacityも減っている
> len=4 cap=4 [5 7 11 13]

// capacity以上にlengthを伸ばそうとするとエラーになる
> panic: runtime error: slice bounds out of range [:5] with capacity 4

// capacityを超えて要素を追加しようとすると、capacityが以前の2倍になる
> len=5 cap=8 [5 7 11 13 4]


#sliceの初期値
func main() {
    var s []int
    fmt.Println(s, len(s), cap(s))
    if s == nil {
        fmt.Println("nil!")
    }
}

> [] 0 0
> nil!

スライスとmake

makeを使って、lengthとcapacityを指定して、スライスを生成できる
要素の初期値は0


func main() {
    a := make([]int, 5)
    printSlice("a", a)

    b := make([]int, 0, 5)
    printSlice("b", b)

    c := b[:2]
    printSlice("c", c)

    d := c[2:5]
    printSlice("d", d)
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}

 スライスの中にスライス

import (
    "fmt"
       // 文字列の操作
    "strings"
)

func main() {
    // Create a tic-tac-toe board.
    board := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
    }
    fmt.Println(board)

    board[0][0] = "X"
    board[2][2] = "O"
    board[1][2] = "X"
    board[1][0] = "O"
    board[0][2] = "X"

    for i := 0; i < len(board); i++ {

        // スライス内の要素を" "でつないで出力
        fmt.Printf("%s\n", strings.Join(board[i], " "))
    }

}

> [[_ _ _] [_ _ _] [_ _ _]]
> X _ X
> O _ X
> _ _ O
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0