エンジニアもどきの雑記

メモ帳です。きっと。macアプリ配信windowsでもできるようになるまで絶対にメイン機にしないマン。特筆しない限り環境は【win10home,i5-7200u,8g,64bit,巨乳が好き】

GoLangやるpart5

前回
dddpga1.hateblo.jp
前に配列をちょこっとした時にちょこっとだけ話した参照型をやる。


slice,map,channelの三つが定義されてる。
と、それぞれを作成するためのmakeって関数がある。

じゃあ一個ずつ見てく。

slice


var s []int c#とかで見るものによく似てるね。

main.go

package main

import "fmt"

func main() {
        s := make([]int, 10)
        fmt.Println(s)
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
[0 0 0 0 0 0 0 0 0 0]

sliceのmakeの使い方が以下

make(型, 要素数と容量)
make(型, 要素数, 容量)


型は配列と同様[]を付けるのを忘れずに。
配列に似てる。
代入と参照も配列と同様。

けど内部的、というかプログラム的には配列とは全く別のものなので注意。
pythonもタプルだのなんだのってこういうの多いよね。
使いこなせばすごい便利なのだろうけど自分はまだまだ。

で、要素数はわかるけど(配列でいう[]の中に書いてる数字だよね?)、容量ってのは何か。
要するに、宣言したsliceが確保しているメモリの範囲。っていうか容量か。

確認してみる。
len()cap()って関数がある。
それぞれが要素数と容量を取得する関数。

main.go

package main

import "fmt"

func main() {
        s := make([]int, 10)
        fmt.Println(len(s))

        s2 := make([]int, 3, 5)
        fmt.Println(len(s2))
        fmt.Println(cap(s2))
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
10
3
5


s2は要素数は3でintのデフォルト値0が三つ入ったスライスが出来上がるけど、
メモリ上は5つ分まで確保していて、後に拡張する必要がないってこと。
多分。

容量と要素数が同じスライスを拡張しようとする時、
また別の容量を持ったメモリ上にそのままコピーするため、
大きなパフォーマンスになるため、こういった容量指定が大事になる。
らしい。
こういうこと書いてある本って非常に良い。

配列みたいな以下のような書き方もできる

s := []int{1,2,3}

配列の[...]intみたいな書き方と似すぎてて最初は困惑する。


簡易スライス式


cとかpythonでできるhoge[0:2]みたいなのができる。
cに近い書き方って言われるくらいだし当たり前か。

main.go

package main

import "fmt"

func main() {
        s := []int{1, 2, 3, 4, 5}
        one := s[0:2]
        two := s[0:]
        three := s[:3]
        four := s[:]

        fmt.Println(one)
        fmt.Println(two)
        fmt.Println(three)
        fmt.Println(four)
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
[1 2]
[1 2 3 4 5]
[1 2 3]
[1 2 3 4 5]


基本的に[インデックスのどこから:インデックスのどこまで]で、指定がなかったら
最初から最後まで。
また、要素数外の数を指定するとエラー。
で、切り取ることができる。
ptyhonの何桁区切り、って書き方はできないのかな?
調べてみよう

ちょいとググってきたけどどうやらなさそう。
pythonだと[0:0:3]みたいにもう一つ指定できてインデックスをその数字区切りで取得できたりする。
あんまり使ったことないけど。


さて、前に要素数の違う配列を宣言した別の配列に代入したら型が違うとエラー、ってのを
やったと思うんだけど、どうやら要素数まで含めて型になるらしいからあのようなエラーがでるみたい。

が、スライスは可変長配列を表現するものなのでそこが少し違う。
っていうか配列との一番の違いはそこだ。


スライスへの要素の追加をする。

main.go

package main

import "fmt"

func main() {
        s := []int{1, 2, 3, 4, 5}

        s = append(s, 10)
        fmt.Println(s)

        s2 := append(s, 22, 33, 44)
        fmt.Println(s2)

        s3 := make([]int, 0, 10)
        s3 = append(s3, 111, 222)
        fmt.Println(s3)
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
[1 2 3 4 5 10]
[1 2 3 4 5 10 22 33 44]
[111 222]


見たまんまなんだけど、注意しないといけないのは、append()は代入しないとエラーになる。
そこだけ。そこは不便な気がする。
append自体は末尾に追加。
s2へ代入しているのは複数を追加しているのがわかる。
また、s3については先ほどやった要素数の確保のやつで一応やってみた

と、スライスは↑を見てわかる通り、容量を超えた場合自動で容量を増やしてくれる。
故の可変長。


copy


名前の通り一括でコピーできる関数が用意されている。
とりあえず触ってみる。

main.go

package main

import "fmt"

func main() {
        s := []int{1, 2, 3, 4, 5}
        s2 := []int{22, 44}

        s3 := copy(s, s2)
        fmt.Println(s3)
        fmt.Println(s)

        s4 := make([]int, 3)
        copy(s4, []int{1, 2, 3})
        fmt.Println(s4)
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
2
[22 44 3 4 5]
[1 2 3]


s3の値が2になってるのは、copyが返却しているのはコピーした数(今回だとs2の要素数)を返すから。
その次に出しているのが実行後の結果。
また、appendと違って代入しなくていい。っていうのが最後のs4のところ。
返してる数字があれだからか。

copyはスライスに対してスライスの値をコピーする。
素数が足りなくても上書く。


完全スライス式


先ほど簡易スライス式の時に、pythonの[0:0:4]みたいな書き方の紹介を
少しだけしたけど、同じ書き方で違う使い方のものがあった。

簡単にいうと容量の指定。
というのも、簡易スライス式で出したスライスは、式の実行前に定義した状態の容量がそのままになってる。
それを変更するための三つ目の数字を与えることができる。

実際に見てみる。

main.go

package main

import "fmt"

func main() {
        s := []int{1, 2, 3, 4, 5}
        fmt.Println(len(s))
        fmt.Println(cap(s))

        s = append(s, 6, 7)
        fmt.Println(len(s))
        fmt.Println(cap(s))

        s2 := s[1:3]
        fmt.Println(len(s2))
        fmt.Println(cap(s2))

        s3 := s[1:3:4]
        fmt.Println(len(s3))
        fmt.Println(cap(s3))
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
5
5
------
7
10
------
2
9
------
2
3


ちょっと見づらいから-----って入れた。
先ほど使用したlencapで要素数と容量をそれぞれ確認している。
見てほしいのはs2s3の結果。
同じだけ抜き出してるけどcapの結果が違う。これはmaxで容量を調整しているため。
また、max自体は要素数の最初からどこまで、の数字であるので注意。

スクリプト言語だともう少し踏み込まないと意識しないメモリへの意識が早めにくるけど
こっちが本来のプログラミングだと思う。
実際現場出てると(人とプログラミングしてると)php書けるけど動きはわかりません、って人も多い。
もっと言えば読めるけど一から書けませんってのも超多いけど。
これが最近のウェブ業界未経験から育てます、の弊害な気もする。

まぁ俺もそういう会社で業界入ったんだけど。
ようはやる気の問題。
俺もまだまだわからないことだらけだけど。


ちょっと長くなってきたのでここまで。
次回はmapと、できたらchannelも。
前回interfaceもしたいって書いたけどもっと後になりそう。
参照型の後にfor文とかになりそう。

では次回。

次回
dddpga1.hateblo.jp