「Go/条件分岐と繰り返し」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
130 行
 
==== range 節を伴った For文 ====
For文がrange節を伴った場合、スライス・配列・文字列・マップ・チェンネルなどのコレクションの要素を1つづつ(breakやreturnで中途退出しない限り)すべてイテレートします。
{{Main|Go/文#range_節のある文の場合}}
{{See also|Go/文#range_節のある文の場合}}
;[https://play.golang.org/p/uaLR8z9coDM コード例]:<syntaxhighlight lang="go">
 
===== range 節がスライスの場合 =====
;[https://play.golang.org/p/utKbU8y5gfd スライス]:<syntaxhighlight lang=go highlight="8,12" line>
package main
 
137 ⟶ 140行目:
 
func main() {
var s := make([]int, 6)
 
for i, _ := 1; i <= 5;range i++s {
s[i] = append(s, 10 * i)
}
fmt.Printf("%#v\n", s)
for i, e := range s {
fmt.Println(i, e)
149 ⟶ 152行目:
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
[]int{0, 10, 20, 30, 40, 50}
0 10
10 200
21 3010
32 4020
43 5030
4 40
5 50
</syntaxhighlight>
: この例ではintのスライス s を宣言し、最初のForで一つづつappendで要素に添え字の10倍の値増や代入しています。
: range 節は多値代入の右辺となり、左辺の最初に添え字が次に要素の値が入ります。
: 不要な項は、8行目のようにブランク識別子( _ )を起きます。
 
===== range 節が配列の場合 =====
;[https://play.golang.org/p/dDGwALQ6u8g 配列]:<syntaxhighlight lang=go highlight="6" line>
package main
 
import "fmt"
 
func main() {
s := [6]int{}
 
for i, _ := range s {
s[i] = 10 * i
}
fmt.Printf("%#v\n", s)
for i, e := range s {
fmt.Println(i, e)
}
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
[]int{0, 10, 20, 30, 40, 50}
0 0
1 10
2 20
3 30
4 40
5 50
</syntaxhighlight>
: 宣言部分以外は、スライスと同じです。実行結果も全く同じです。
: このようにスライスと配列は区別しにくいですが、配列は '''append''' で要素数を増したり、部分要素を返したりできません(部分要素を得ようとするとスライスが返る)。
: 性能的には、スライスは要素のアクセスは線形時間 O(n)、配列の要素のアクセスは定数時間 O(1)であることが大きな違いです。
: 配列 <var>s</var> をスライスに変換するには、<syntaxhighlight lang=go highlight="6" inline>s[:]</syntaxhighlight>とします。
: スライスを配列に変換する方法は、現時点(go-1.17.1)ではありません(配列の要素数はコンパイル時に確定することが要求されている)。
 
===== range 節が文字列の場合 =====
;[https://play.golang.org/p/USwXt9hEPi0 文字列]:<syntaxhighlight lang=go highlight="8,12,13" line>
package main
 
import "fmt"
 
func main() {
s := "abcd"
 
fmt.Printf("%#v\n", s)
for i, e := range s {
fmt.Println(i, e)
}
for _, e := range s {
fmt.Print(string(e))
}
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
"abcd"
0 97
1 98
2 99
3 100
abcd
</syntaxhighlight>
: 文字列にFor・rangeを適用するとインデックスと1文字をイテレートします。
: 返される文字は Rune型 です(Goには char型 はありません)
: Rune型は整数型なので単純に文字列化すると数字になります。
: Rune型を文字コード(厳密にはコードポイント)として文字化するには、string() で型変換します。
 
===== range 節がマップの場合 =====
;[https://play.golang.org/p/_mZJ5xsEgEm マップ]:<syntaxhighlight lang=go highlight="7,16,21,23" line>
package main
 
import "fmt"
import "sort"
 
func main() {
s := map[int]string{}
 
for i := 0; i < 6; i++ {
s[i] = fmt.Sprintf("str%v", 10*i)
}
fmt.Printf("%#v\n", s)
for i, e := range s {
fmt.Println(i, e)
}
keys := []int{}
for i := range s {
keys = append(keys, i)
}
fmt.Printf("%#v\n", keys)
sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
fmt.Printf("%#v\n", keys)
for i := 0; i < len(keys); i++ {
fmt.Println(i, s[i])
}
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
map[int]string{0:"str0", 1:"str10", 2:"str20", 3:"str30", 4:"str40", 5:"str50"}
2 str20
3 str30
4 str40
5 str50
0 str0
1 str10
[]int{4, 5, 0, 1, 2, 3}
[]int{0, 1, 2, 3, 4, 5}
0 str0
1 str10
2 str20
3 str30
4 str40
5 str50
</syntaxhighlight>
: ここでは、キーを整数値を文字列とするマップ <var>s</var> を宣言しました
: マップはキーとマップに様々な型を使えますが、1つのマップではキー・値それぞれの型はすべて一致している必要があります。
: マップの要素へのアクセスは定数時間 O(1)です。
: マップにFor文を適用した場合、すべてのキーと値のペアを順にイテレートできますが、順序は不定です。
: キーの値順に要素を取り出したい場合は、一旦すべてのキーをスライスに取り出し、そのスライスをソートした上で、スライスをループさせることで実現します。
 
===== range 節がチャンネルの場合 =====
;[https://play.golang.org/p/q0vXC0MFreF チェンネル]:<syntaxhighlight lang=go highlight="6,10,13" line>
package main
 
import "fmt"
 
func main() {
c := make(chan int)
go func() {
defer close(c)
for i := 0; i < 5; i++ {
c <- i
}
}()
for v := range c {
fmt.Println(v)
}
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
0
1
2
3
4
</syntaxhighlight>
: For・rangeにチェンネルを適用するとクローズされるまで受信した値をイテレートします。