Go言語入門メモ（型について）

# 背景
前回の[Go言語入門メモ](https://qiita.com/ynarasak/items/10a903366e697b67a20c)に続いて、Go言語勉強を継続実施。今回はコードの書き方（構文）を覚えながら型について整理しつつゴリゴリコードを書いてみた。

# 型確認コード
Go言語で用意されている型について整理した結果が出力されるコード


```go:type.go
package main

import (
  "fmt"
  "math"
//  "strings"
  "reflect"
)

type El struct {
    X interface{}
}

const intSize = 32 << (^uint(0) >> 63)

func main() {
    var bl bool
    var str string
    var ui8 uint8
    var bt byte
    var ui16 uint16
    var ui32 uint32
    var ui64 uint64
    var i8 int8
    var i16 int16
    var i32 int32
    var rn rune
    var i64 int64
    var f32 float32
    var f64 float64
    var cpx64 complex64
    var cpx128 complex128
    var ui uint
    var i int
    var uip uintptr
    // reflectで動的にmathを呼び出せるかチャレンジしたがダメだったのでコメントアウト ここから
    //mathObj := math // こんなことはできない
    //method := reflect.ValueOf(&mathObj).MethodByName("MinInt8") // こんなことはできない
    //var v = method.Call([]reflect.Value{}) //こんなことはできない
    //var v = math.MinInt8 // こんなことはできない
    // reflectで動的にmathを呼び出せるかチャレンジしたがダメだったのでコメントアウト ここまで

    names := []string{"bl","str","ui8","bt","ui16","ui32","ui64","i8","i16","i32","rn","i64","f32","f64","cpx64","cpx128","ui","i","uip"}
    elements := []El{El{bl},El{str},El{ui8},El{bt},El{ui16},El{ui32},El{ui64},El{i8},El{i16},El{i32},El{rn},El{i64},El{f32},El{f64},El{cpx64},El{cpx128},El{ui},El{i},El{uip}}
    typeReader(names, elements)
}

func typeReader(names []string, elements []El) {
   // map定義
   maxIntMap := map[string]uint64{
      "ui8": math.MaxUint8,
      "ui16": math.MaxUint16,
      "ui32": math.MaxUint32,
      "ui64": math.MaxUint64,
      "i8": math.MaxInt8,
      "i16": math.MaxInt16,
      "i32": math.MaxInt32,
      "i64": math.MaxInt64,
    }
    maxFloatMap := map[string]float64{
      "f32": math.MaxFloat32,
      "f64": math.MaxFloat64,
    }
    maxEtcMap := map[string]string{
      "str": "stringはintの最大が文字列長の最大と考えられる",
      "bt": "byteはuint8のalias",
      "rn": "runeはint32のalias",
      "ui": "動作環境のOSに依存します。32bit OR 64bit",
      "i": "動作環境のOSに依存します。32bit OR 64bit",
      "uip": "ポインタの値を表現するに十分なサイズの符号なし整数",
      "cpx64": "複素数。実数部と虚数部として内部にそれぞれfloat32の値を持つ",
      "cpx128": "複素数。実数部と虚数部として内部にそれぞれfloat64の値を持つ",
    }
    minIntMap := map[string]int64{
      "ui8": 0,
      "ui16": 0,
      "ui32": 0,
      "ui64": 0,
      "i8": math.MinInt8,
      "i16": math.MinInt16,
      "i32": math.MinInt32,
      "i64": math.MinInt64,
    }
    minEtcMap := map[string]string{
      "str": "MINという表現は当てはまらない",
      "bt": "byteはuint8のalias",
      "rn": "runeはint32のalias",
      "ui": "動作環境のOSに依存します。32bit OR 64bit",
      "i": "動作環境のOSに依存します。32bit OR 64bit",
      "uip": "ポインタの値を表現するに十分なサイズの符号なし整数",
    }
    fmt.Printf("この実行環境のOSは[%d]bitです\n", intSize)

    for i := 0; i < len(elements); i++ {
        fmt.Printf("%-6s TYPE -> [%-10s] ", names[i], reflect.TypeOf(elements[i].X))
        fmt.Print("DEFAULT VALUE -> [")
        fmt.Print(elements[i].X)
        fmt.Print("]")
        if val, ok := maxIntMap[names[i]]; ok {
          fmt.Printf(" MAX VALUE -> [%d] MIN VALUE -> [%d]", val, minIntMap[names[i]])
        }
        if val, ok := maxFloatMap[names[i]]; ok {
          fmt.Printf(" MAX VALUE -> [%f]", val)
        }
        if val, ok := maxEtcMap[names[i]]; ok {
          fmt.Printf(" MAX VALUE -> [%s] MIN VALUE -> [%s]", val, minEtcMap[names[i]])
        }
        //文字列前方一致で場合分けする場合のコード
        //if strings.HasPrefix(names[i], "u") {
        //}
        fmt.Println("")
    }
}
```

[このコードを実行してみる](https://play.golang.org/p/UbLMEEmNXMB)


# 実行結果
```shell-session
% go run type.go
この実行環境のOSは[64]bitです
bl     TYPE -> [bool      ] DEFAULT VALUE -> [false]
str    TYPE -> [string    ] DEFAULT VALUE -> [] MAX VALUE -> [stringはintの最大が文字列長の最大と考えられる] MIN VALUE -> [MINという表現は当てはまらない]
ui8    TYPE -> [uint8     ] DEFAULT VALUE -> [0] MAX VALUE -> [255] MIN VALUE -> [0]
bt     TYPE -> [uint8     ] DEFAULT VALUE -> [0] MAX VALUE -> [byteはuint8のalias] MIN VALUE -> [byteはuint8のalias]
ui16   TYPE -> [uint16    ] DEFAULT VALUE -> [0] MAX VALUE -> [65535] MIN VALUE -> [0]
ui32   TYPE -> [uint32    ] DEFAULT VALUE -> [0] MAX VALUE -> [4294967295] MIN VALUE -> [0]
ui64   TYPE -> [uint64    ] DEFAULT VALUE -> [0] MAX VALUE -> [18446744073709551615] MIN VALUE -> [0]
i8     TYPE -> [int8      ] DEFAULT VALUE -> [0] MAX VALUE -> [127] MIN VALUE -> [-128]
i16    TYPE -> [int16     ] DEFAULT VALUE -> [0] MAX VALUE -> [32767] MIN VALUE -> [-32768]
i32    TYPE -> [int32     ] DEFAULT VALUE -> [0] MAX VALUE -> [2147483647] MIN VALUE -> [-2147483648]
rn     TYPE -> [int32     ] DEFAULT VALUE -> [0] MAX VALUE -> [runeはint32のalias] MIN VALUE -> [runeはint32のalias]
i64    TYPE -> [int64     ] DEFAULT VALUE -> [0] MAX VALUE -> [9223372036854775807] MIN VALUE -> [-9223372036854775808]
f32    TYPE -> [float32   ] DEFAULT VALUE -> [0] MAX VALUE -> [340282346638528859811704183484516925440.000000]
f64    TYPE -> [float64   ] DEFAULT VALUE -> [0] MAX VALUE -> [179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000]
cpx64  TYPE -> [complex64 ] DEFAULT VALUE -> [(0+0i)] MAX VALUE -> [複素数。実数部と虚数部として内部にそれぞれfloat32の値を持つ] MIN VALUE -> []
cpx128 TYPE -> [complex128] DEFAULT VALUE -> [(0+0i)] MAX VALUE -> [複素数。実数部と虚数部として内部にそれぞれfloat64の値を持つ] MIN VALUE -> []
ui     TYPE -> [uint      ] DEFAULT VALUE -> [0] MAX VALUE -> [動作環境のOSに依存します。32bit OR 64bit] MIN VALUE -> [動作環境のOSに依存します。32bit OR 64bit]
i      TYPE -> [int       ] DEFAULT VALUE -> [0] MAX VALUE -> [動作環境のOSに依存します。32bit OR 64bit] MIN VALUE -> [動作環境のOSに依存します。32bit OR 64bit]
uip    TYPE -> [uintptr   ] DEFAULT VALUE -> [0] MAX VALUE -> [ポインタの値を表現するに十分なサイズの符号なし整数] MIN VALUE -> [ポインタの値を表現するに十分なサイズの符号なし整数]
```


# 型確認コードを作成して気づいた点

- `interface{}` を用いることで型を意識せずにやりとり可能！
- 使わないものを`import`するとエラーになる。例えば`strings`を利用しないのに`import`すると`imported and not used: "strings"`とエラーになり教えてくれる親切。
- Mapのキーが存在するかを調べる方法。[参考](https://qiita.com/suin/items/4cb1da71237fc55a06ee)
- OSビットを調べる方法。[参考](https://qiita.com/ruiu/items/28c77ed483cec365fe84)
- `reflect`を用いて動的呼び出しが可能になるが、既に用意されている関数の動的呼出はできない模様。[参考](https://k0kubun.hatenablog.com/entry/2014/12/06/173227)