【第三回Go言語学習備忘録】スライスで連続表示!(rangeもあるよ!)

2月 12, 2022

どもです。最近買ったダウンがめちゃくちゃ暖かくてコスパも最高でした。ユニクロ様バンザイ。saisaiです。


今回はGo言語でスライスについて学んだので、こちらの学習内容を備忘録として残しておきたいと思います。
配列も学んだのですが、スライスの方がサイズ変換の柔軟性もあり使いやすそうだったのでこちらにフォーカスを当てて記事にしたいと思います。

スライスとはなんぞや!

“一つの変数に複数の値を宣言して臨機応変に出力できる"のがスライスかなと。
百聞は一件にしかず、まずはさくっとコードを作成してみました。
ついでにそれぞれの出力結果について解説も付けてみました。

package main

import "fmt"

func main() {
	s := []string{"s", "a", "i", "s", "a", "i"}

	fmt.Println(s)
 //スライスの中身を全て表示 -> [s a i s a i]
	fmt.Println(s[0])   
  //スライスの先頭を表示(順番は0から始まる) -> s
	fmt.Println(s[0:3]) 
  //先頭(0)から2(3-1)を表示 -> [s a i] (0,1,2)
	fmt.Println(s[:3])  
  //上記と同じ意味 -> [s a i]
	fmt.Println(s[3:])  
  //3以降を全て表示 -> [s a i] (3,4,5)
	fmt.Println(s[:])   
  //スライスの中身を全て表示 -> [s a i s a i]
}

まずは基本的なスライスの使い方です。スライスには複数の定義方法がありますが今回は以下のように定義します。値は文字列なので、それぞれをダブルクォーテーションで囲みます。

s := []string{"s", "a", "i", "s", "a", "i"}
//変数名 := []型{値,値,...}


実際にスライスの中身を出力する場合は以下のように指定します。

変数名[番号の指定]

スライスを含め配列系の処理をするコードを書くときは、番号の考え方に注意です。
番号は先頭"0″から与えられており、そこから(0,1,2…)と続いていきます。
また、値を連続して複数指定する場合は用途に合わせて書き方を変更します。

上のサンプルコードに指定方法の例を記載しております。末尾の番号は(-1)してして指定すると考えると分かりやすそうです。(本来の考え方ではなさそうですが…。)

スライスに値を追加する!

それでは一度定義したスライスに値を追加していきましょう。値の追加には"append"を使用します。
コードは以下の通り。

package main

import "fmt"

func main() {
	s := []string{"s", "a", "i", "s", "a", "i"}

	fmt.Println(s) //[s a i s a i]

	s = append(s, "s", "a", "i")
  //append(スライスで指定した変数名,追加する値,追加する値,追加する値...)

	fmt.Println(s) //[s a i s a i s a i]
}

“sai"がもう一つ追加されましたね!

makeを使用して初期化されたスライスを作成する!

次に、予め"長さ"と"容量"を指定して初期化したスライスを作っておく方法です。
まずは"長さ5″かつ"容量5″であるスライスを作成してみます。

package main

import "fmt"

func main() {
	s1 := make([]int, 5, 5)
	fmt.Println(s1) //[0 0 0 0 0]
	fmt.Println(len(s1)) //5
	fmt.Println(cap(s1)) //5
}

たしかに指定した通りのスライスが作成されていることがわかります。値にはint型の初期値である"0″が代入されていますね。しかし、 “長さ"と"容量"というものがまだ具体的になんなのか分からなかったのでさらに調べてみました。

スライスの長さと容量について!

スライスの長さを変更して"長さ"と"容量"の変化をみてみます。

package main

import "fmt"

func main() {
	s1 := make([]int, 5, 5) 
	fmt.Println(s1) //[0 0 0 0 0] int方は初期値が"0"
	fmt.Println(len(s1)) //5
	fmt.Println(cap(s1)) //5

	s2 := s1[2:4]
	fmt.Println(s2) //[0 0]
	fmt.Println(len(s2)) //2
	fmt.Println(cap(s2)) //3
}

スライスで出力する"長さ"を指定すると、"len(s2)"の値もそれに合わせて変化しました。ここから"長さ"とは現在のスライスに含まれる要素の長さだということが分かりました。

では容量はどうでしょう。要領とはそのスライスで確保しているメモリ要領です。予め使用する容量を指定することでパフォーマンスの向上を計ることができるのだと思われます。長さが変更されると当然確保される容量も小さくなります。

ちなみにスライスの長さを追加した場合、もちろん"長さ"と"容量"も変更されます。

package main

import "fmt"

func main() {
	s := make([]int, 5, 5)
	fmt.Println(s) //[0 0 0 0 0]
	fmt.Println(len(s)) //5
	fmt.Println(cap(s)) //5

	s = append(s, 1, 2, 3)
	fmt.Println(s) //[0 0 0 0 0 1 2 3]
	fmt.Println(len(s)) //8
	fmt.Println(cap(s)) //10
}

要素を3つ追加したので"長さが8″そして"容量は10″になりましたね!Go言語の仕様上、確保したメモリ容量を超えると、倍の数値で追加されていくようです。このようにスライスの容量を追加すると、対応するように"長さ"や"容量"が変化していることが分かりますね!

一度に複数のスライスを指定!

複数のスライスを一度に定義できる方法もあるようです。

package main

import "fmt"

func main() {
	var slices = [][]string{
		[]string{"C", "C#", "C++"},
		[]string{"Java", "Scala", "Cotlin"},
		[]string{"Ruby", "Python", "PHP"},
	}
	fmt.Println(slices)
 //[[C C# C+] [Java Scala Cotlin] [Ruby Python PHP]]
 fmt.Println(slices[0])
 //[C C# C+]
}

使用することが予め決まっているスライスなどはさくっと先に定義してしまって番号を使用して呼び出すというのもアリなのかもしれません!

rangeを使ったスライスの応用

さて、ここからは"range"を使ってスライスの中身を順に取り出してみようと思います。
まずはコードです。

package main

import "fmt"

func main() {
	l := []string{"Windows", "Mac", "Linux"}

	for _, v := range l { 
		fmt.Printf("My OS is %v\n", v)
	}
}
//出力結果は以下の通り
//My OS is Windows
//My OS is Mac
//My OS is Linux

スライスの中身を順々に取り出して変数に代入することができました!このようにスライスの中身を順に取り出したいときは"range"を使用するようです。ちなみにrangeの値を代入する変数は本来スライスの順番と値を代入しますが、順番を代入する変数は使用しない場合アンダースコアで省略可能です。値の変数はマストなので注意しましょう。

ひとこと

今回はスライスについて学習したので備忘録として残しておきました。トテモムズカシイ…。


学習しているときは"?"でいっぱいの頭も、このように記事にしてアウトプットするとどんどん理解が深まります。
スライスはサンプルコードを漁っている時でもよく見かけるものなので、しっかり自身に落とし込んでいきたいと思います!


ここまで読んでいただいきありがとうございました。


-saisai-


↓本日のオススメ

Golang

Posted by CY