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-08-10

概要

  • 前回の続き。
  • 今回はデータ型について学習した
    • 基本データ型 - int, bool, float, rune, string
    • 合成型 - 配列, リスト, Map, 構造体
  • javaやts(typescript)との違いも言及しつつ進める

インプットの教材

基本データ型

  • 整数や浮動小数等は、型の種類が複数あるが、とりあえずデフォルト型のintとfloatを押さえればよいか
  • 他の基本データ型はjavaと大体一緒。runeが聞きなじみがないが、文字を格納するcharのことだった。

変数の宣言

  • var 変数名 データ型 = 値 の形式。データ型は省略すると値に応じたデフォルトの型となる
  • その他、一括宣言var{}や、関数内宣言 := 値がある。関数内宣言はjavaやtsでは見ないのでチェック。
変数宣言とデータ型の例

	// 整数
	var i1 int = 10
	var i2 = 10
	// 浮動小数
	var f1 float64 = 10.5
	var f2 = 10.5
	// bool
	var b1 bool = true
	var b2 = false
	// string
	var s1 = "hello"
	var s2 string = "hello2"
	// rune
	var r1 = 'h'
	var r2 rune = 'h'

	// 一括宣言
	var i3, s3 = 20, "abc"
	var (
		i4 = 10
		i5 int
		s4,s5 = "aa","bb"
	)

	// 関数内での変数宣言
	i6 := 10
  • 暗黙的な型変換は行われない。明示的な型変換を毎回行う。
    • Javaでは、小さい型から大きい型への代入は暗黙的な型変換が行われる。(逆の大きい型から小さい方への変換は明示的な型変換(キャスト)が必要。)
    • Goの場合、型変換を必須にすることでルールをシンプルにした模様。トレードオフで記載が冗長になるが。
型変換
    
	// 型のキャスト
    var i1,f1 = 10, 10.5 // int, float
    //f1 = i1         // NG:暗黙的キャストはできない
	f1 = float64(i1) // OK:int → floatへの変換は明示的に行う。
	b1 = s1 == s2 // bool型は真偽値の結果で入れる。

    // なお、int型からstring(またはその逆)への変換はGoでは互換性がない
	castNum := 10
	//castStr := string(castNum)  //NG


定数の宣言

  • constで行う。const 定数名 = 値
  • 定数名は変数名と同じcamelCase。
    • 大文字から始まるプロパティは、パッケージ外からアクセスできるものを定義するルールらしい。
    • 変数や定数について、宣言方法、命名規則などtsに近い。
  • 定数は、イミュータブルな値のみ設定できる。
    • 基本データ型(リテラル値)は設定できる。イミュータブルな値であるため。
    • 配列や構造体などはイミュータブルな値であるため設定できない。
定数の宣言
	const con1 = "定数"
	const (
		con2 = "const"
		con3 = "const2"
	)

配列とスライス

  • 配列は固定長のデータをリスト管理
  • スライスは可変長のデータリストを管理。基本的にはスライスを使う。(Javaのlist)
  • スライス(配列も)はミュータブルなデータ型であることに注意
  • 値の追加(append)では新しいスライスを作成するため、戻り値への代入が必要
配列、sliceの作成
	// 配列の作成
	var l1 = [3]int{10,20,30}
	var l2 = [...]string{"aa","bb"}
	// スライス
	var s1 = []int{10,20,30}
	// スライスは追加できる(戻り値が必要)
	s1 = append(s1, 40);
  • コピーする場合は、makeで同じ領域の空スライスを作って、copy処理でコピーする方法がよい。
sliceのコピー

	s := []int{10,20,30,40}
	// makeでコピー元と同じ長さの配列を用意
	s2 := make([]int, len(s))
	// copyを実施
	copy(s2,s)
	s2 = append(s2, 50)
    fmt.Println(s, s2) //[10 20 30 40] [10 20 30 40 50]

マップ

  • map[キーの型]値の型で宣言。初期値はnil
  • mapへの追加は、m[key] = 値。keyはなければ追加
  • mapの参照はm[key] 。値がなければデフォルト値を返す。
  • mapの削除は、delete(m, key)。戻り値なし。
	// 宣言
	var m1 map[int]string  // NG: nilマップ。値の追加不可となるためこの宣言はしない。
	m2 := map[int]string{} // OK: 空マップの追加。値の追加可能

	// 値の読み書き
	m2[1] = "値1"
	m2[2] = "値2"
	m2[3] = "値3"
	fmt.Println(m2[2]) // 値2

	// 削除
	delete(m2, 2)
	fmt.Println(m2[2])   // 値なし:nil
	fmt.Println(len(m2)) // 2
  • カンマokイディオム
    • 値と、値の存在可否を取得するイディオム。
      • キーに紐づく値が存在しない場合、値の型のデフォルト値がとれる
      • そのため、値が存在しないのか、デフォルト値を設定しているかの区別をつけるため、存在可否も返す。
    • v, ok :=m[key] の構文で判別ができるようになる。
	m3 := map[string]int{
		"first": 0,
		"second": 1,
	}
	val, ok := m3["first"]
	fmt.Println(val,ok) // 0, true → キーが存在し、値が0
	val2, ok2 := m3["notkey"]
	fmt.Println(val2,ok2) // 0, false → キーがなく、値はデフォルト0

構造体

  • 構造体の継承はできない。(Javaのクラスとは異なる。)
  • type 変数名 struct{}キーワードで作成する(構文はtsのtypeと近しい。structがあるかないか。)
    • typeは型。structが構造体を表す。
	// 構造体の作成
	type human struct {
		name string
		age int
	}
	
	// 初期化
	var taro human
	hanako := human{} //Mapとは違い、varと同様に、0値で初期化。
	takashi := human{"たかし",20}
	yuki := human{name: "ゆき"}

	fmt.Println(taro) // { 0}
	fmt.Println(hanako) // { 0} 
	fmt.Println(takashi) // {たかし 20}
	fmt.Println(yuki) // {ゆき 0}

	// 値の設定
	hanako.name = "はなこ"
	fmt.Println(taro) // {はなこ 0}
  • 無名構造体は変数宣言と同時に作成する。型は定義しないため、structキーワードのみ
	// 無名構造体
	var game struct {
		title string
		price int
	}
	game.title = "FF"
	game.price = 7000

	// 無名構造体 - 初期化時に設定(リテラル代入)
	game2 := struct {
		title string
		memo string
	} {
		title: "DQ",
		memo: "楽しい",
	}
  • 別の型への代入は、構造体の構成が一致する場合可能。
	type human1 struct {
		name string
		age int
	}
	h1 := human1{}

	type human2 struct {
		name string
		age int
	}
	h2 := human2{}

	type human3 struct {
		age int
		name string
	}
	h3 := human3{}

	// 構造体の構成が一致する場合、型変換で代入できる
	h1 = human1(h2) // OK: 一致する
	h1 = human1(h3) // NG: 一致しない。(コンパイルエラー)
	
	// 無名関数の場合は直接代入できる
	var h4 struct {
		name string
		age int
	}
	h1 = h4

おわりに

  • 基本型、配列、スライス、マップ、構造体について学んだ。細かい違いはあれど、概ねJavaやtsと同じ。

    • 宣言方法や、構造体の書き方など、tsの方が構文は近いかも。
    • sliceやMapの種類は一つ、Setはないなど、Goの方がシンプルではある。
      • この辺りは、継承がなく、派生クラスがないからか。
  • ただし、継承がないのは大きな違いに感じる。

    • オブジェクト指向による設計は難しくなりそうなので、大規模開発には向いてなさそう。
    • マイクロサービス化が主流になってきているので、シンプルな設計にしているのかも。
  • 関数内宣言(名称これでいいのか?):=による変数宣言は、Javaやtsにはない構文なので覚えておく。

0
0
2

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?