2020/02/14

[golang]スライスと配列。あるいは配列とスライス。

昨年の記憶からすると、golangのスライスと配列は宣言が似ているものの、同じように使おうとすると怒られる、という代物だった。

あまり考えず、思いつくままに書いてみよう。

01: package main
02: 
03: 
04: func gogo(bababa int[]) {
05: 	for i := 0; i < bababa.length; i++ {
06: 		bababa[i] = i
07: 	}
08: }
09: 
10: func main() {
11: 	var momomo int[];
12: 
13: 	momomo = new int[10];
14: 	gogo(momomo)
15: 	for i := 0; i < momomo.length; i++ {
16: 		fmt.Printf("[%d] = %d\n", i, momomo[i])
17: 	}
18: }
  

はい、コンパイルエラーです。

golangは型を後に書くタイプだったよなー、とか、Javaの配列は型名の後だったよなー、とか、そんなことを考えてやってみたのだが、やっぱりダメだった。

01: package main
02: 
03: import "fmt"
04: 
05: func gogo(bababa []int) {
06: 	for i := 0; i < len(bababa); i++ {
07: 		bababa[i] = i
08: 	}
09: }
10: 
11: func main() {
12: 	var momomo []int
13: 
14: 	momomo = make([]int, 5)
15: 	gogo(momomo)
16: 	for i := 0; i < len(momomo); i++ {
17: 		fmt.Printf("[%d] = %d\n", i, momomo[i])
18: 	}
19: }
  

 

型名の前にスライスであることを表すのだな。
そして、スライスの要素数はlen()。確保済みの要素数はcap()らしい。


for文で要素数の数だけループさせるというのは、最近の言語ではあまりやらん気がする。
でもforeachっぽい書き方をすると代入ができないんじゃなかろうか?

01: package main
02: 
03: import "fmt"
04: 
05: func gogo(bababa []int) {
06: 	for i, value := range(bababa) {
07: 		value = i
08: 	}
09: }
10: 
11: func main() {
12: 	var momomo []int
13: 
14: 	momomo = make([]int, 5)
15: 	gogo(momomo)
16: 	for i, val := range(momomo) {
17: 		fmt.Printf("[%d] = %d\n", i, val)
18: 	}
19: }
  

これはコンパイルエラーになった。
gogo()の方でvalueを使っていないという扱いになったからだ。

01: package main
02: 
03: import "fmt"
04: 
05: func gogo(bababa []int) {
06: 	for i := range bababa {
07: 		bababa[i] = i
08: 	}
09: }
10: 
11: func main() {
12: 	var momomo []int
13: 
14: 	momomo = make([]int, 5)
15: 	gogo(momomo)
16: 	for i, val := range momomo {
17: 		fmt.Printf("[%d] = %d\n", i, val)
18: 	}
19: }
  

これなら通った。

第2戻り値を使わないので、最初は

for i, _ := range bababa {

にしたのだが、これはコンパイルエラーではないものの、警告されてしまった。
省略するものらしい。

 

range(momomo)は、vscodeのフォーマッタを使ったら括弧を外されてしまった。
しかし、len(momomo)はダメらしい。

lenは関数で、rangeは関数ではないということだろうか?

https://golang.org/ref/spec#RangeClause

rangeはRnageClauseというものらしい。れんじくらうぜ?

なんでもかんでもrangeが使えるわけではない。array, slice, string, map, channel。
戻り値も、1stと2ndでちゃんと決められているそうだ。

rangeはfor文専用のようだ。
だからlenとは扱いが違うのだろう。

 

これで終わろうと思ったが、よくわからないサンプルがあった。

01: package main
02: 
03: import "fmt"
04: 
05: func gogo(bababa []int) {
06: 	for i := range bababa {
07: 		 bababa[i] = 10 + i
08: 	}
09: }
10: 
11: func lolo(bababa []int) {
12: 	i := 3
13: 	for i, bababa[i] = range bababa {
14: 		
15: 	}
16: }
17: 
18: func main() {
19: 	var momomo []int
20: 
21: 	momomo = make([]int, 5)
22: 	gogo(momomo)
23: 	lolo(momomo)
24: 	for i, val := range momomo {
25: 		fmt.Printf("[%d] = %d\n", i, val)
26: 	}
27: }
  

ちなみに、オリジナルはこうだ。

i = 2
x = []int{3, 5, 7}
for i, x[i] = range x {  // set i, x[2] = 0, x[0]
	break
}
// after this loop, i == 0 and x == []int{3, 5, 3}

 

breakがあってもなくても、なんか動作がよくわからない。
今日は眠たいので、また次回だ。

 

あ、配列のこと書き忘れた!
まあ、それも含めた次回だな。。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。