0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Go 基本文法【参照型編】

Last updated at Posted at 2023-06-22

はじめに

今回はGoの基本文法である「参照型」についてです。

目次

  1. 参照型 Slices : スライス(可変長配列)
  2. 参照型 Maps : マップ(連想配列)
  3. 参照型 Range : レンジ(反復処理)
  4. 参考文献

参照型 Slices : スライス(可変長配列)

スライスは可変長配列を指します。
スライスの宣言方法は以下です。
配列(Arrays)と違い、スライスは [ ] の中に大きさを指定しません。

 ① var 変数名 []型
 ② var 変数名 []型 = []型{初期値1, ..., 初期値n} 
 ③ 変数名 := 配列[start:end] 
   ⇨ 配列(またはスライス)のstartから(end - 1)を取り出す事でスライスを生成
 ④ 変数名 := 配列[len(要素数):end] ⇨ startをlen(要素数)で指定
 ⑤ make で要素数を決めた後、一部の要素へデータを格納
main.go
package main

import "fmt"

func main() {
	// ①
	var s1 []string
	fmt.Println(s1) // => []

	// ②
	s2 := []int{1, 2, 3, 4, 5}
	fmt.Println(s2) // => "[1 2 3 4 5]"

	// ③
	s3 := s2[0:3]
	fmt.Println(s3) // => "[1 2 3]"

	// ④
	s4 := s2[len(s2)-2 : 5]
	fmt.Println(s4) // => "[4 5]"

	// ⑤
	s5 := make([]int, 5)
	s5[0] = 3
	fmt.Println(s5) // => "[3, 0, 0, 0, 0]"
}

[start:end]の指定パターンは以下のとおりです。

パターン 意味
Slice[start:end] start から end - 1 まで
Slice[start:] start から最後尾まで
Slice[:end] 先頭から end - 1 まで
Slice[:] 先頭から最後尾まで

ちなみに、スライスとスライス元となった配列の要素は共有されます。
なので、スライスの要素を変更するとスライス元の配列要素に対しても変更がかかリます

main.go
func main() {
	slice_target := [...]string{"Hello", "Go"}
	slice := slice_target[0:2] // スライスの生成

	slice[1] = "PHP" // slice[1]の要素を変更
	fmt.Println(slice_target) // => [Hello PHP] // slice_target の要素も変更されている
}

スライスへの要素追加は組み込み関数append()を使用することで可能です。

new_slice = append(slice, 追加要素)
main.go
func main() {
	slice_target := []string{"Hello", "Go"}
	new_slice := append(slice_target, "PHP") // slice_target に "PHP" を追加

	fmt.Println(new_slice)    // => [Hello Go PHP]
	fmt.Println(slice_target) // => [Hello Go] // 元の値は変わっていない。
}

ここで、スライスで使われるlength(長さ)capacity(容量)について解説です。
 ・length : length を指定したスライスの要素数
 ・capacity : capacity を指定したスライスの生成元の要素数
 length と capacity はlen()cap()という式を使います。

main.go
func main() {
	slice_target := [...]string{"Hello", "Go"}
	s1 := slice_target[0:1]

	fmt.Println(s1)      // => Hello
	fmt.Println(len(s1)) // => 1 // s1 の要素数は1つなので1を返す。
	fmt.Println(cap(s1)) // => 2 // s1 の生成元の要素数は2つなので2を返す。
}

また、スライスには完全スライス型というものがあります。
lowhighmaxの3つのパラメータを使ってスライスを生成します。

slice[low:high:max]
// この時のlenとcapは各々以下で算出される
// len() : high - low
// cap() : max - low
main.go
func main() {
	slice_targat := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	s1 := slice_targat[2:4:4] // == "[3, 4]"
	fmt.Println(len(s1))      // == 2
	fmt.Println(cap(s1))      // == 2

	s2 := slice_targat[2:4:6] // == "[3, 4]"
	fmt.Println(len(s2))      // == 2
	fmt.Println(cap(s2))      // == 4
}

スライスは型が一致している場合、他のスライスへ代入することができます。

main.go
func main() {
	slice_target := []string{"Hello", "Go"}
	var s1 []string // slice_target と同型である s1 を作成

	s1 = slice_target // slice_target を s1 へ代入

	fmt.Println(s1) // => [Hello Go]
}

スライスのゼロ値nilです。
nilスライスは、0 の length と capacity を持っており、元となる配列は持っていません。

main.go
func main() {
	var slice_target []int
	fmt.Println(slice_target, len(slice_target), cap(slice_target)) // => [] 0 0

	// 条件式では nil と比較
	if slice_target == nil {
		fmt.Println("nil!") // => nil!
		// slice_target の値が nil の場合に nil! を表示
	}
}

スライスは組み込み関数のmake()を使って定義することもできます。

make([], len, cap)
main.go
func main() {
	slice := make([]int, 3, 3) // スライス生成
	slice[1] = 1 // => slice[1] へ1を代入
	fmt.Println(slice) // => [0 0 0]
}

参照型 Maps : マップ(連想配列)

マップは連想配列を指します。要素と値がセットになっています。
マップの生成方法は以下の通りです。

var マップ名 map[要素の型]値の型
マップ名 := make(map[要素の型]値の型)

色々と書いてみました。特徴・記法については以下の通りです。

main.go
package main

import "fmt"

func main() {
	// マップ生成 : ※出力値は五十音順にソートされる
	m := map[string]int{"japan": 100, "usa": 200, "canada": 300}
	fmt.Println(m) // => map[canada:300 japan:100 usa:200]

	// 空のマップ生成、値を代入
	m2 := make(map[string]int)
	m2["apple"] = 1
	fmt.Println(m2) // => map[apple:1]

	// 値の参照
	fmt.Println(m["japan"]) // => 100

	// 値の追加・更新
	m["italy"] = 500
	fmt.Println(m) // => map[canada:300 italy:500 japan:100 usa:200]
	m["japan"] = 150
	fmt.Println(m) // => map[canada:300 italy:500 japan:150 usa:200]

	// 値の存在チェック
	v1, check := m["korean"]
	fmt.Println(v1, check) // => 0 false

	v2, check := m["japan"]
	fmt.Println(v2, check) // => 100 true

	// 値の消去
	delete(m, "italy")
	fmt.Println(m) // => map[canada:300 japan:150 usa:200]

	// マップから要素のみを抽出
	fmt.Println(extract_keys(m)) // => [japan usa canada]

	// マップから値のみを抽出
	fmt.Println(extract_values(m)) // => [150 200 300]

	// マップを多次元配列へ変換
	fmt.Println(convert_ma(m)) // => [[japan 150] [usa 200] [canada 300]]

	// 特定要素の値のみを抽出
	keys := []string{"usa", "canada"}
	fmt.Println(extract_pinpoint_values(m, keys)) // => [200 300]

	// マップ同士をマージ(結合)
	merge1 := map[string]string{"key1": "val1", "key2": "val2"}
	merge2 := map[string]string{"key3": "val3"}
	fmt.Println(merge(merge1, merge2)) // => map[key1:val1 key2:val2 key3:val3]
}

// マップから要素のみを抽出
func extract_keys(m map[string]int) []string {
	ks := []string{}
	for k, _ := range m {
		ks = append(ks, k)
	}
	return ks
}

// マップから値のみを抽出
func extract_values(m map[string]int) []int {
	vs := []int{}
	for _, v := range m {
		vs = append(vs, v)
	}
	return vs
}

// マップを多次元配列へ変換
func convert_ma(m map[string]int) []interface{} {
	a := []interface{}{}
	for k, v := range m {
		a = append(a, []interface{}{k, v})
	}
	return a
}

// 特定要素の値のみを抽出
func extract_pinpoint_values(m map[string]int, keys []string) []int {
	vs := []int{}
	for _, k := range keys {
		vs = append(vs, m[k])
	}
	return vs
}

// マップ同士をマージ(結合)
func merge(m1, m2 map[string]string) map[string]string {
	ans := map[string]string{}

	for k, v := range m1 {
		ans[k] = v
	}
	for k, v := range m2 {
		ans[k] = v
	}
	return (ans)
}

参照型 Range : レンジ(反復処理)

for ループに利用する range は、スライスやマップを反復処理するために使います。
range の生成方法は以下の通りです。

for 要素,  := range スライスまたはマップ名 {}

for と range の扱い方は主に3種類です。

 ①要素と値を取り出す
 ②要素だけを取り出す(値を```_```で出力しないようにする)
 ③値だけを取り出す(要素を```_```で出力しないようにする)

以下はスライスを for と range で取り出しています。

main.go
package main

import "fmt"

func main() {
    // ①
    var country = []string{"japan", "usa", "canada", "italy"}
	for index, value := range country {
		fmt.Println(index, value) // => 0 japan 1 usa 2 canada 3 italy
	}

    // ②
	var country = []string{"japan", "usa", "canada", "italy"}
	for index, _  := range country {
		fmt.Println(index) // => 0 1 2 3
	}

    // ③
	var country = []string{"japan", "usa", "canada", "italy"}
	for _, value := range country {
		fmt.Println(value) // => japan usa canada italy
	}
}

_は省略可能です。

for index := range country

マップは以下のように取り出します。

main.go
func main() {
	m := map[string]int{"japan":100, "usa":200, "canada": 300}
	for index, value := range m {
		fmt.Println(index, value) // => japan 100 usa 200 canada 300
	}
}

参考文献

A Tour of Go
Go言語(golang) スライスと配列の使い方
逆引きGolang (マップ)
Go 言語のマップ (map)
【Go入門】forとrangeを使った取り出し方について

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?