前回の記事でポインタの必要性を勉強しました。
まだ読んでない方がいらっしゃいましたら是非読んでやってください
実務でGo
を使ってく中で聞きなれないスライスという言葉を知って、それが何やら配列と関係性があるみたいなので今回はそれについて調べたので、今回はそれをまとめていこうとおもいます
今回の目次は以下の通りです
- 配列とは
- スライスとは
- 配列とスライスの違い
今回の記事はハンズオンでやっていくといいと思いますので、こちらのサイトから実際に手を動かしてみてください!
最後まで読んでいただけると幸いです!
配列とは
Go
における配列とはどんなものかというと、同じデータタイプのデータを保存するためのもので、固定長のものです。
といってもよくわからないので詳しく見ていきましょう。
配列の作り方
まず配列を作ってみましょう。
配列の作成の仕方は以下の2つの書き方があります。
// 1つ目の書き方
character := [3]string{
"エレン",
"ミカサ",
"リヴァイ",
}
// 2つ目の書き方
character := [...]string{
"エレン",
"ミカサ",
"リヴァイ",
}
1つ目の書き方では配列の長さ(要素数とも言える)を3に固定にして配列を定義しました。
2つ目の書き方では、配列の中に...
を使用しています。
これは要素数を勝手に数えてくれる書き方で、要素数に応じた数字がこの中で勝手に定義されると考えてください。
そしてこの配列の1番の特徴は、宣言した配列の個数より、個数を増やしたり減らしたりできないことが1番の特徴です
実際に値を追加してみます。
package main
import "fmt"
func main() {
character := [3]string{
"エレン",
"ミカサ",
"リヴァイ",
}
character = append(character, "ジーク")
}
// => error[first argument to append must be a slice; have character (variable of type [3]string)]
想定通りエラーが出てきました。
エラー分を翻訳すると、
「追加する最初の引数はスライスでなければならず、文字([3]string 型の変数)を持つ。」
要は、配列じゃ値は変更できないですよ!。スライスにしてください!ってことなんですね。
このことが1番初めに述べた同じデータタイプのデータを保存するためのもので、固定長のものという意味です。
ですがこの配列は、公式ドキュメントのブログによるとあまり使われることはないみたいです。
以下がそれの抜粋です。
Arrays are not often seen in Go programs because the size of an array is part of its type, which limits its expressive power.
Goのプログラムでは、配列はあまり見かけません。配列のサイズは型の一部であり、表現力が制限されるからです。
まぁ確かにあんまり使う用途ないですよね笑
逆によく使われるのはスライスです。
次はスライスについて解説していきます。
スライスとは
配列のセクションを読んだ方なら薄々感じているかもしれませんが、配列でできない値の変更や作成ができるのがスライスの特徴です。
配列は、固定長だったのに対して、スライスは、可変長と言われます。
スライスをどう書くかというと、以下のように書きます。
// 1つ目の書き方
character := []string{
"エレン",
"ミカサ",
"リヴァイ",
}
// 2つ目の書き方
character := make([]string, 3){
"エレン",
"ミカサ",
"リヴァイ
実際に値を追加してみましょう。
値を追加する際に使うメソッドは、append
メソッドを使います。
package main
import "fmt"
func main() {
character := []string{
"エレン",
"ミカサ",
"リヴァイ",
}
fmt.Println(append(character, "ジーク"))
}
// => [エレン ミカサ リヴァイ ジーク]
ちゃんと値が出力されています。このようにスライスは元の値を変えることができるのがメリットですね!
次の章でスライスと配列の違いを見ていきます
配列とスライスの違い
この2つの違いは2つあります。
- 値が変更できるか否か
- 参照渡しか値渡しかどうか
1. 値が変更できるか否か
こちらは先ほどまでのセクションまでの解説を読んでいただければわかると思うのでここで省略します。
2. 参照渡しか値渡しかどうか
スライスは参照渡ししかできなくて、配列では値渡ししかできません。
そもそも参照渡しと値渡しとはなんでしょうか?
この参照渡しと値渡しは、関数の引数などの話でよく出てきます。
参照渡しは、値を渡す代わりにメモリの場所を渡します。
メモリの場所を渡してしまうため、関数の中で処理されて変更された値それ自体が変わってしまいます。
値渡しは、変数の値をメソッドに渡しますが、その値を別のメモリ位置に、コピーして、そのコピーをメソッドに渡します。
そのため、メソッド内部の変数に何が起こっても、元の変数の値には影響がありません。
文章で読んでみてもよくわからないと思うので、実際にコードを見て確かめてみます。
最初に参照渡しを見ていきます。先ほども述べたように、参照渡しはスライスで使えます。
今回は、ミカサをアルミンに変更してみます。
package main
import "fmt"
func ChangeMikasaIntoAlmin(character []string) {
character[1] = "アルミン"
}
func main() {
characterSlice := []string{
"エレン",
"ミカサ",
"リヴァイ",
}
ChangeMikasaIntoAlmin(characterSlice)
fmt.Println(characterSlice)
値が変更されている
// => [エレン アルミン リヴァイ]
}
参照渡しは、メモリの場所を渡してその中身を処理するため、データが更新されたり、削除されたり、作成することができるようになります。
これがスライスの参照渡しです。
それに対して、値渡しは、配列で使うことができます。
値渡しは、値を別のメモリ位置に、コピーして、そのコピーをメソッドに渡すため、元の値が変更されることがありません。
実際にコードを見てみましょう。
package main
import "fmt"
func ChangeMikasaIntoAlmin(character [3]string) {
character[1] = "アルミン"
}
func main() {
characterSlice := [3]string{
"エレン",
"ミカサ",
"リヴァイ",
}
ChangeMikasaIntoAlmin(characterSlice)
fmt.Println(characterSlice)
値は変わっていない
// => [エレン ミカサ リヴァイ]
}
まだ、参照渡しと値渡しのイメージが付いてない方は、こちらの記事の最初の方に、画像があるので、これがわかりやすい画像なので参照してみてください!
以上です!
何か間違いなどありましたら、コメントで教えていただけると幸いです。
【参考資料】