LoginSignup
11
6

More than 5 years have passed since last update.

Go言語初心者が学んだ基礎的な文法まとめ

Last updated at Posted at 2017-10-24

Go言語の型の種類

こんにちは。僕もGoを勉強し始めることになりました。
学んだ文法をまとめたいと思います。

変数

型を宣言して使う

//型を宣言する
var str string
str = "hello"
fmt.Println(str)//=>hello
fmt.Println(reflect.TypeOf(str))//=>string

型推論

//型は推論される
var str = "hello"
fmt.Println(str) //=>hello
fmt.Println(reflect.TypeOf(str)) //=>string

varを省略する

//変数宣言と初期化を行う場合に、var と型宣言を省略して「:=」演算子を用いることができる。
str := "hello"
fmt.Println(str)//=>hello
fmt.Println(reflect.TypeOf(str))//=>string

型の種類

主にこんな感じ。

int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex64 complex128
bool byte
string rune

型の変換

型の変換には"strconv"を使用する。

文字列から数値に変換する

import (
    "fmt"
    "strconv"
    "reflect"
)

func main() {
    var i int
    i, _ = strconv.Atoi("100")
    fmt.Println(i) //=>100
    fmt.Println(reflect.TypeOf(i)) //=>int

}

数値から文字列に変換する

import (
    "fmt"
    "strconv"
    "reflect"
)

func main() {
fmt.Println(strconv.Itoa(100)) //=>100
fmt.Println(reflect.TypeOf(strconv.Itoa(100))) //=>string
}

interface型

全ての型と互換性を持っているinterface{}型

var obj interface{}

obj = 123                                                              // int
obj = "str"                                                            // string
obj = []string{"linux", "windows", "android"}                          // slice
obj = make(chan string)                                                // channel
obj = func(val int) string { return fmt.Sprintf("number is %d", val) } // function

Go言語 - 空インターフェースと型アサーション

ポインタ型

func callByValue(i int) {
    i = 20 // 値を上書きする
}

func callByRef(i *int) {
    *i = 20 // 参照先を上書きする
}

func main() {
    var i int = 10
    callByValue(i) // 値を渡す
    fmt.Println(i) // 10
    callByRef(&i) // アドレスを渡す
    fmt.Println(i) // 20
}

はじめてのGo―シンプルな言語仕様,型システム,並行処理

ポインタ型とそうではない型の違いは、構造体の部分で書きます。

型の確認

型の確認には、reflectを使う。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    fmt.Println(reflect.TypeOf(1))   //=>int
    fmt.Println(reflect.TypeOf("test"))   //=>string
    fmt.Println(reflect.TypeOf([]string{"a", "b", "c"}))  //=>[]string
}

配列

型とサイズを決めて配列を宣言。

var arr [5]int
//5つのものが入る配列arrを宣言
//6以上入るとエラー。
var arr [5]int
arr[5] = 5
fmt.Println(arr) //=>invalid array index 5 (out of bounds for 5-element array)

宣言した数以上のものを入れることができない。
柔軟に対応するためには、どうするか=>sliceを使う。

slice

配列は入れることのできる数が決まっているが、sliceは決まっていない。可変長である。

sliceの定義方法

a:=[]T{}
a:=make([]T,len)

sliceの使い方

fruits := []string{"apple", "orange", "lemon"}
fmt.Println(fruits) // => [apple orange lemon]
fruits = append(fruits, "peach")
//追加の際には、appendを使う。
fmt.Println(fruits) //=>[apple orange lemon peach]
//peachが追加された。

map(連想配列)

Golangではハッシュ(連想配列)のことをmapと呼ぶ。

package main

import (
    "fmt"
)

func main() {
    m := map[string]int{"japanese": 68, "english": 70, "math": 90}
    fmt.Println(m) //=>map[japanese:68 english:70 math:90]
    fmt.Println(m["japanese"]) //=>68
    //mapからキーの値を取り出す
    m["science"] = 100
    //要素を追加する
    fmt.Println(m) //=>map[japanese:68 english:70 math:90 science:100]
}

構造体

struct定義

structを使ってそのフィールドが持つ値を決定することができる。

type Animal struct {
    Name string
    Age  int
}

クラスのようなもの。

structを初期化する

初期化の方法にもいくつかあるので、見ていきます。

newを使う

さっき作ったAnimalを初期化します。初期化したanimalに値を入れます。

package main

import "fmt"

type Animal struct {
    Name string
    Age  int
}

func main() {
    animal := new(Animal)//:= でポインタ型
    animal.Name = "Tanaka"//NameにTanakaを代入
    animal.Age = 10//Ageに10を代入

    fmt.Println(animal)
    //=>&{Tanaka 10}
}

ポインタ型でTanakaと10というものが返ってきます。

ポインタ型で初期化する

package main

import "fmt"

type Animal struct {
    Name string
    Age  int
}

func main() {
    animal := &Animal{
        Name: "Tanaka",
        Age: 10,
    }
    fmt.Println(animal)
    //=>&{Tanaka 10}
}

これでも同じ結果です。

そのまま初期化して使う

package main

import "fmt"

type Animal struct {
    Name string
    Age  int
}

func main() {
    animal := Animal{
        Name: "Tanaka",
        Age: 10,
    }
    fmt.Println(animal)
    //=>{Tanaka 10}
}

今回はポインタ型ではなく、そのまま出力されました。

構造体の初期化方法で何が違うのか

これは一体何が違うのでしょう。

以下の記事に違いが書かれていました。引数として使った場合などに変化が見られるそうです。
https://qiita.com/kmtr/items/1e7caf92aa8bb587906d

試してみます。

package main

import "fmt"

type Animal struct {
    Name string
    Age  int
}

func changeAge1(animal1 Animal, age int) {
    animal1.Age = age
    fmt.Printf("%p\n", &animal1)
}

func changeAge2(animal2 *Animal, age int) {
    animal2.Age = age
    fmt.Printf("%p\n", animal2)
}

func main() {

    animal1 := Animal{
        Name: "Tanaka",
        Age: 10,
    }
    fmt.Printf("%p\n", &animal1)
    changeAge1(animal1, 100)

    animal2 := &Animal{
        Name: "Tanaka",
        Age: 10,
    }

    fmt.Printf("%p\n", animal2)
    changeAge2(animal2, 100)
}

結果

0xc42000a060
0xc42000a080
0xc42000a0a0
0xc42000a0a0

なるほど、確かに以下のように構造体を初期化した場合は、引数として使うと、構造体の値を変更した際にポインタが変わってしまうようです。

    animal1 := Animal{
        Name: "Tanaka",
        Age: 10,
    }

構造体の初期化方法というよりポインタの扱い方な気がします。
Goのポインタが参考になります。

for文

package main

import "fmt"

func main() {
    sum := 0
    for i := 0; i < 10; i++ {
        sum += i
    }
    fmt.Println(sum)
}

if文

package main

import (
    "fmt"
    "math"
)

func sqrt(x float64) string {
    if x < 0 {
        return sqrt(-x) + "i"
    }
    return fmt.Sprint(math.Sqrt(x))
}

func main() {
    fmt.Println(sqrt(2), sqrt(-4))
}

switch文

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Print("Go runs on ")
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case "linux":
        fmt.Println("Linux.")
    default:
        // freebsd, openbsd,
        // plan9, windows...
        fmt.Printf("%s.", os)
    }
}

終わりに

Go言語触ってみましたが、正直まだまだ見えてきません。
いつか見えてくる日がくるのだろうか。その時を待ちたいと思う。

11
6
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
11
6