Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
94
Help us understand the problem. What are the problem?

【Go】基本文法総まとめ

概要

プログラミング言語Goの基本文法を学習シリーズです。

No 記事
1 【Go】基本文法①(基礎)
2 【Go】基本文法②(フロー制御文)
3 【Go】基本文法③(ポインタ・構造体)
4 【Go】基本文法④(配列・スライス)
5 【Go】基本文法⑤(Maps・ Range)
6 【Go】基本文法⑥(インターフェース)
7 【Go】基本文法⑦(並行処理)
8 〜〜【Go】基本文法総まとめ「今ココ」〜〜

パッケージ

パッケージ(package)ポイント

  • Goのプログラムはパッケージ(package)によって成り立っている。
  • importを使用する事で必要なパッケージ(package)をインポートする事が可能。
  • Goでは最初の文字が大文字で始まるものは、外部パッケージから参照が可能(Exported names)。 (例えば以下のPiはmathパッケージからエクスポートされたもの。)

参考コード

package main

import (
    "fmt"
    "math"
)
//import "fmt"
//import "math" の様に個別でもimportが可能

func main() {
   fmt.Println(math.Pi) //=> 3.141592653589793
}

Functions(関数)

Goでは関数は以下の様に定義される。

参考コード

func  <関数名>([引数]) [戻り値の型] {
    [関数の本体]
}

Functions(関数)のポイント

  • 引数の戻り値の型を書く必要がある。(ex1)
  • 関数が2つ以上の同種類の引数を伴う場合、以下の様に型の省略する事が可能。(ex2)
  • 関数は複数の値を返すことができる。(ex3)

参考コード

func main() {
    fmt.Println(hello("Hello World")) //=> Hello World
    fmt.Println(hello2("Hello", "World")) //=> Hello World
    fmt.Println(multipleArgs("Hello", "World")) //=> World Hello
}
//ex1:引数の戻り値の型を書く必要がある
func hello(arg string) string{
     return arg
}
//ex2:関数が2つ以上の同種類の引数を伴う際、型の省略する事が可能
func hello2(arg1, arg2 string) string {
     return arg1 + " " + arg2
}
//ex3:関数は複数の値を返すことができる
func multipleArgs(arg1, arg2 string)(string, string){
    return arg2, arg1
}

Variables(変数)

Variables(変数)ポイント

  • varによって変数を宣言し、型の明示が必要である。(ex1)
  • 初期値を渡した状態で変数を宣言すると型の明示を省略が可能。(ex2)
  • 関数内では:=を利用することでより短いコードで変数の宣言を行うことが可能。(ex3)

参考コード

//ex1:`var`によって変数を宣言し、型の明示が必要である。
var lang string 
//※変数に初期値を与えないとゼロ値(Zero values)が設定されます。(数値型には0、bool型にはfalse、string型には""(空の文字列)が与えられる。

//ex2:初期値を渡した状態で変数を宣言すると型の明示を省略が可能。
var lang2 = "Golang"//初期値を渡す。

func main() {
    //ex3:関数内では`:=`を利用することでより短いコードで変数の宣言を行うことが可能
    lang3 := "JS" 
    fmt.Println(lang, lang2, lang3) //=> Golang JS
}

Constants(定数)

Constants(定数)ポイント

  • 定数は、constキーワードを使用して宣言する。
  • 定数は、文字(character)文字列(string)boolean数値(numeric)のみで使用可能。
  • 定数は:=を使用して宣言することはできない。

参考コード

const Num = 2

func main(){
    const Greetings = "Hello World"
    fmt.Println(Greetings) // => Hello World
    fmt.Println(Num) // => 2
}

Forループ

Forループポイント

  • 使用時に条件式等を囲む()は必要ありませんが処理を囲む{}は必要。

参考コード

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

If(条件分岐)

ifステートメントは、forのように、条件の前に、評価するための簡単なステートメントを書くことができる。(ここで宣言された変数は、ifのスコープ内だけで有効。)

参考コード

package main 

import "fmt"

func condition(arg string)string{
  if v := "GO"; arg == v {
    return "This is Golang"
  }else{
    return "This is not Golang"
  }
}
func main(){
    fmt.Println(condition("Swift")) //=> This is not Golang
}

Switch(条件分岐)

Switch(条件分岐)ポイント

  • 選択されたcaseだけを実行してそれに続く全てのcasedefaultは実行されない。
  • switchの前に何も条件を書かない場合はswitch trueと書くのと同じ。

参考コード

func main(){
    fmt.Println(condition("Go")) //This is Go
}

func condition(arg string) string{
    switch arg {
    case "Ruby":
        return "This is Ruby"
    case "Go": //これ以降のcaseやdefaultは実行されない。
        return "This is Go"
    case "JS":
        return "This is JS"
    default:
        return "I don't know what this is"
    }
}

Defer(遅延実行)

deferへ渡した関数の実行を呼び出し元の関数の終わり(returnする)まで遅延させる。

Defer(遅延実行)ポイント

  • deferへ渡した関数が複数ある場合、その呼び出しはスタックされ、新しいデータ→古いデータの順番で実行される。(=最初にdeferされた行が一番最後に実行される。)

参考コード

package main 

import "fmt"

func main(){
    defer fmt.Println("Golang") //defer1
    defer fmt.Println("Ruby") //defer2
    fmt.Println("JS") 
    //=> JS
    //=> Ruby
    //=> Golang
}

ポインタ

ポインタ(pointer)ポイント

  • ポインタはメモリのアドレス情報のこと。
  • Goでは&を用いることで変数のアドレスの取得が可能。(ex1)
  • *を使用する事でポインタを値にとったポインタ変数の宣言が可能。(ex2)
  • ポインタ型変数名の前に*をつけることで変数の中身へのアクセスが可能。(ex3)

参考コード

func main(){
    var lang string 
    lang = "Go" 
    //ex1:`&`を用いることで変数のアドレスの取得が可能
    fmt.Println(&lang) //=> 0x1040c128

    //ex2:`*`を使用する事でポインタを値にとったポインタ変数の宣言が可能
    var langP *string 
    langP = &lang
    fmt.Println(langP)//=> 0x1040c128

    //ex3:ポインタ型変数名の前に`*`をつけることで変数の中身へのアクセスが可能
    fmt.Println(*langP) //=> Go
}

Structs(構造体)

Structs(構造体)ポイント

  • classに似た役割を提供する。(関連する変数をひとまとめにする。)
  • typestructを使用して定義する。(参考コード① ex1)
  • 複数の初期化方法が存在する。(参考コード① ex2)
  • 構造体内にメソッドmethodを定義できる。(参考コード② ex3)
  • 継承に似た機能として構造体の埋め込みが可能(参考コード③ ex4)

参考コード①

// ex1: typeとstructを使用して定義する。
type Person struct {
   name string 
   age int
}

func main(){
//ex2:複数の初期化方法が存在する
    //初期化方法①:変数定義後にフィールドを設定する
    var mike Person
    mike.name = "Mike"
    mike.age = 23

    //初期化方法②: {} で順番にフィールドの値を渡す
    var bob = Person{"Bob", 35}

    //初期化方法③:フィールド名を : で指定する方法
    var sam = Person{age:89, name: "Sam"}

    fmt.Println(mike, bob, sam) //=> {Mike 23} {Bob 35} {Sam 89}
}

参考コード②

//ex3:構造体内にメソッドを定義できる
//普通の関数と違うのはレシーバ引数(下記の「(ele Person)」)の部分だけ。
func(ele Person)intro(arg string) string {
    return arg + " I am" + " " + ele.name
}

func main(){
    bob := Person{"Bob", 85}
    fmt.Println(bob.intro("Hello!")) //=>Hello! I am Bob
}

参考コード③

type Person struct {
    name string 
    age int
} 

func(ele Person)intro(arg string) string {  //Personのメソッド
    return arg + " I am" + " " + ele.name
}

//ex4:継承に似た機能として構造体の埋め込みが可能
  //構造体UserにPersonを組み込む。
type User struct {
    Person
}

func(ele User)intro(arg string) string { //Userのメソッド
    return "User No." + arg + " " + ele.name
}

func main(){
    bob := Person{"Bob", 85}

    var user1 User
    //組み込みによりnameの定義が可能
    user1.name = "Bob"

    fmt.Println(bob.intro("Hello!")) //=> Hello! I am Bob
    fmt.Println(user1.intro("1")) //=> User No.1 Bob
}

Arrays(配列)

Arrays(配列)ポイント

  • 配列とは、同じ型を持つ値(要素)を並べたもの。(ex1)
  • 複数の宣言方法がある。(ex2)
  • 最初に宣言した配列のサイズを変えることはできない。(ex3)

配列の基本的な宣言方法

 var 変数名 [長さ]
 var 変数名 [長さ] = [大きさ]{初期値1, 初期値n} 
 変数名 := [...]{初期値1, 初期値n}

参考コード

//ex1:配列とは、同じ型を持つ値(要素)を並べたもの
//ex2:複数の宣言方法がある

//宣言方法(1)
var arr1 [2]string 
//宣言方法(2)
var arr2 [2]string = [2]string{"Golang", "Ruby"}
//宣言方法(3)
var arr3 = [...]string{"Golang", "Ruby"}

func main(){
    arr1[0] = "Golang"
    arr1[1] = "Ruby"
    fmt.Println(arr1, arr2, arr3) //=> [Golang Ruby] [Golang Ruby] [Golang Ruby]
}

Slices(スライス)

Slices(スライス)ポイント

  • 配列とは異なり長さ指定の必要なし。(参考コード① ex1)
  • 別の配列から要素を取り出し参照する形での宣言やmake()を利用した宣言が可能。(参考コード① ex2)
  • 配列とは異なり要素の追加が可能。(参考コード① ex3)
  • 長さ(length)容量(capacity)の両方を持っている。(参考コード② ex4)
  • 型が一致している場合、他のスライスに代入することが可能。(参考コード② ex5)
  • スライスのゼロ値はnil。(参考コード② ex6)

参考コード①

func main(){
    //参照用配列
    var arr[2]string = [2]string{"Ruby","Golang"}

    //ex1:配列とは異なり長さ指定の必要なし
    var slice1 []string //スライス(1)
    var slice2 []string = []string{"Ruby", "Golang"} //スライス(2)

    //ex2:配列から要素を取り出し参照する形での宣言が可能
    var slice3 = arr[0:2] //スライス(3)

    //ex2:make()を利用した宣言が可能
    var slice4 = make([]string,2,2) //スライス(4)

    //ex3:配列とは異なり要素の追加が可能
    //append は新しいスライスを返すことに注意
    slice5 := [] string{"JavaScript"}
    newSlice := append(slice5, "Ruby") //sliceに"Ruby"を追加

    fmt.Println(slice1,slice2,slice3,slice4, slice5, newSlice) //=>[] [Ruby Golang] [Ruby Golang] [ ] [JavaScript] [JavaScript Ruby]
}

参考コード②

func main(){
    slice := []string{"Golang", "Ruby"}

    //ex4:長さ(length)と容量(capacity)の両方を持っている。
    //長さ(length) は、それに含まれる要素の数
    //容量(capacity) は、スライスの最初の要素から数えて、元となる配列の要素数
    fmt.Println(len(slice)) //=> 2
    fmt.Println(cap(slice)) //=> 2

    //ex5:型が一致している場合、他のスライスに代入することが可能。
    var slice2[]string //sliceと同型slice2を作成
    slice2 = slice //sliceをslice2に代入
    fmt.Println(slice2) //=>[Golang Ruby]

    //ex6:スライスのゼロ値は nil
    var slice3 []int
    fmt.Println(slice3, len(slice), cap(slice)) //=> [] 0 0

    if slice3 == nil {
        fmt.Println("nil!") //=> nil! 
        //sliceの値がnilの場合にnil!を表示する。
    }
}

Maps(連想配列)

Maps(連想配列)ポイント

  • Maps(連想配列)キー (key)というデータを使って要素を指定するデータ構造である。
  • 複数の宣言方法が存在する。(参考コード① ex1)
  • 初期値を指定しない場合、変数はnil(nil マップ)に初期化される。(参考コード① ex2)
  • 要素の挿入や削除が行える。(参考コード② ex3)

参考コード①

func main(){
    //ex1複数の宣言方法が存在する

    //①組み込み関数make()を利用して宣言
    //make(map[キーの型]値の型, キャパシティの初期値)
    //make(map[キーの型]値の型)

    map1 := make(map[string]string)
    map1["Name"] = "Mike"
    map1["Gender"] = "Male"

    //②初期値を指定して宣言
    //var 変数名 map[key]value = map[key]value{key1: value1, key2: value2, ..., keyN: valueN}
    map2 := map[string]int{"Age":25,"UserId":2}

    //ex2初期値を指定しない場合、変数はnil(nil マップ)に初期化される
    var map3 map[string]string

    fmt.Println(map1, map2, map3) //=>map[Gender:Male Name:Mike] map[Age:25 UserId:2] map[]
}

参考コード②

func main(){
    //ex3:要素の挿入や削除が行える

    //連想配列の作成
    var mapEx = map[int]string{1:"Go",2:"Ruby"}
    fmt.Println(mapEx) //=> map[2:Ruby 1:Go]

    //要素の挿入や更新
    mapEx[3] = "Javascript"
    fmt.Println(mapEx) //=> map[1:Go 2:Ruby 3:Javascript]

    //要素の取得
    fmt.Println(mapEx[2]) //=> Ruby

    //要素の削除
    delete(mapEx,3)
    fmt.Println(mapEx) //=> map[2:Ruby 1:Go]
}

Range(forrange節)

Rangeポイント

  • スライスやマップに使用すると反復毎に2つの変数を返す。(ex1)
  • スライスの場合、1つ目の変数は インデックス(index)で、2つ目は要素(value)である。(ex2)
  • マップの場合、1つ目の変数はキー(key)で、2つ目の変数はバリュー(value)である。(ex3)
  • インデックスや値は、_へ代入することで省略することが可能。(ex4)

参考コード

//スライスとマップの作成 
var slice1 = []string{"Golang", "Ruby"}
var map1 = map[string]string{"Lang1":"Golang", "Lang2":"Ruby"}

func main(){
    //ex1:スライスやマップに使用すると反復毎に2つの変数を返す。
    //ex2:スライスの場合、1つ目の変数は `インデックス(index)`で、`2つ目は要素(value)`である。
    for index, value := range slice1{
        fmt.Println(index,value)
        //=> 0 Golang
        //=> 1 Ruby
    }

    //ex3:マップの場合、1つ目の変数は`キー(key)`で、2つ目の変数は`バリュー(value)`である。
    for key, value := range map1{
        fmt.Println(key, value)
        //=> Lang1 Golang
        //=> Lang2 Ruby
    }

    //ex4:インデックスや値は、 _ へ代入することで省略することが可能。

    for _,value := range map1{
        fmt.Println(value)
        //=> Golang
        //=> Ruby
    }
}

Interface(インターフェース)

Interface(インターフェース)ポイント

  • 任意の型が「どのようなメソッドを実装するべきか」を規定するためのもの。
  • インターフェースの定義の内容は、単なるメソッドリストである。
  • オブジェクト指向言語でいうところのポリモーフィズムと同様の機能を実現可能。

参考コード①ではPersonPerson2という構造体があり、各構造体にintro()メソッドが定義されており、各構造体がそれぞれintro()を実行するためのIntroForPerson()IntroForPerson2()と呼ばれるメソッドを持っている。

参考コード①

type Person struct {} //Person構造体
type Person2 struct {} //Person2構造体

//Person構造体のメソッドintro()
func (p Person) intro() string{ 
    return "Hello World"
}

//Person2構造体のメソッドintro()
func (p Person2) intro() string{
     return "Hello World"
}

//Person構造体のメソッドintro()を実行するメソッド
func IntroForPerson(arg *Person){
    fmt.Println(arg.intro())
}

//Person2構造体のメソッドintro()を実行するメソッド
func IntroForPerson2(arg *Person2){
    fmt.Println(arg.intro())
}

func main(){
  bob := new(Person)
  mike := new(Person2) 

  IntroForPerson(bob) //=> Hello World
  IntroForPerson2(mike) //=> Hello World
}

現状ではIntroForPersonIntroForPerson2の同じ動きをするメソッドが存在しており冗長である。
そこで、参考コード②の様に重複するメソッドをInterface(インターフェース)に括り出す事ができる。

参考コード②

type Person struct {} //Person構造体
type Person2 struct {} //Person2構造体

type People interface{
    intro()
}

func IntroForPerson(arg People) {
     arg.intro();
}

//Person構造体のメソッドintro()
func (p *Person) intro() { 
    fmt.Println("Hello World")
}

//Person2構造体のメソッドintro()
func (p *Person2) intro() {
     fmt.Println("Hello World")
}

func main(){
  bob := new(Person)
  mike := new(Person2) 

  IntroForPerson(bob) //=> Hello World
  IntroForPerson(mike) //=> Hello World
}

goroutine(ゴルーチン)

goroutine(ゴルーチン)ポイント

  • Go言語のプログラムで並行に実行されるもののこと。
  • 関数(またはメソッド)の呼び出しの前にgoを付けると、異なるgoroutineで関数を実行することが可能。(ex1)
  • runtime.NumGoroutine()を使用する事で現在起動しているgoroutine(ゴルーチン)の数を知ることが可能。(ex2)

参考コード

package main 

import( 
 "fmt"
 "log"
 "runtime"
)
func main(){
    fmt.Println("Hello World")
    //ex1:関数(またはメソッド)の呼び出しの前にgoを付けると、異なるgoroutineで関数を実行することが可能。
    go hello()
    go goodMorning()
    //ex2:runtime.NumGoroutine()を使用する事で現在起動しているgoroutine(ゴルーチン)の数を知ることが可能。
    log.Println(runtime.NumGoroutine()) 
    //=> Hello World
    //=> 2009/11/10 23:00:00 3
    //3がgoroutineの数。
    //ここではmain, hello, goodMorningの3つを指す。
}

func hello(){
    fmt.Println("Hello")
}

func goodMorning(){
    fmt.Println("Good Morning")
}

channel(チャネル)

channel(チャネル)ポイント

  • 組み込み関数make()を使用する事で生成可能。(参考コード① ex1)
  • チャネルオペレータの<-を用いる事で値の送受信が可能。(参考コード① ex2)
  • 送信がchannel<-valueで受信が<-channel(参考コード① ex2+)
  • channel(チャネル)は値の交換および同期という通信機能を兼ね備えており、ゴルーチンが予期しない状態とならないことを保証する。(参考コード② ex3)

参考コード①

func main(){
    //ex1:組み込み関数`make()`を使用する事で生成可能。
    ch := make(chan string) 

    //ex2:<-を用いる事で値の送受信が可能。
    //ex2+:作成したチャネルchに値を送信。
    go func(){ ch <- "str"}()

    //ex2+:チャネルchから値を受信
    msg := <- ch
    fmt.Println(msg) //=>str
}

参考コード②

func main(){
    //ex3:ゴルーチンが予期しない状態とならないことを保証する。

    ch := make(chan bool) //bool型のチャネルchを作成

    // ゴルーチンとして以下の関数を起動。
    //完了時にchannelの型であるboolの値を送信する事で、チャネルへ通知。
    go func(){
        fmt.Println("Hello")
        ch <- true // 通知を送信。値は何でも良い(boolの型であれば)
    }()

    <- ch //=>Hello  
    // channelの型であるboolの値を受け取るまでの完了待ち。送られてきた値は破棄
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
94
Help us understand the problem. What are the problem?