LoginSignup
1
1

More than 1 year has passed since last update.

GO言語基礎①(package/function/for/if/switch/struct/point/arrays/slice)

Last updated at Posted at 2021-05-04

Go言語のメリット・デメリット

メリット

  • 文法がシンプルでわかりやすい
    • ライブラリが豊富なため簡潔に書くことができる
  • 処理速度が速い
    • 直接機械語に変換するためコンパイルが早い
    • 並列処理を簡潔に書くことができる。goroutinechannelを利用することで大量データの並列処理が可能
  • シングルバイナリ、クロスコンパイルにより環境依存を減らすことができる

デメリット

    throw new Exception(...)

goでは以下のような記載になります。

// 何かの処理の戻り値にエラーが存在する場合
if err != nil {
    // ログ出力で処理終了
    log.Fatal(err)
}

Javaとの違い

クラスではなく構造体で処理を紐付ける

クラスで行いたい処理としては以下のことがメインとなります。

  • 処理毎によるメソッドの切り分け
  • 処理に必要な関数、変数、定数の定義

Go言語ではstructを用いて行います。

package main

import (
    "fmt"
)

type Human struct {
    name string
    age  int
}

func (h Human) SayName() string {
    return h.name + "です。"
}

func main() {
    h := Human{"Mike", 10}
    fmt.Println(h, h.name, h.age)
    fmt.Println(h.SayName())
}
実行結果
{Mike 10} Mike 10
Mikeです。

上記ではHumanというstructを利用してクラス変数を定義しています。
Humanにたいしてあたいを入れることにより、その変数、クラス関数を利用することができます。

継承が存在しない(似たような機能Embeddedは存在する)

goにおいて継承は存在しません。その代わりにEmbeddedは存在します。
厳密にはクラスと違う部分もあるのですが、気になる場合は下記記事を参考にしてください。
Go言語で「embedded で継承ができる」と思わないほうがいいのはなぜか?
今回はHumanを親クラス、Japaneseを子クラスとして記述します。

package main

import (
    "fmt"
    "strconv"
)

type Human struct {
    name string
    age  int
}

type Japanese struct {
    Human
    weight int
}

func (h Human) SayName() string {
    return h.name + "です。"
}

func (h Human) SayAge() string {
    return strconv.Itoa(h.age) + "です。"
}

func (j Japanese) SayName() string {
    return "初めまして" + j.name + "です。"
}

func New(name string, age int, weight int) *Japanese {
    return &Japanese{Human{name, age}, weight}
}

func main() {
    // 初期化 
    j := New("Mike", 20, 55)
    // 親の関数を呼び出せていること
    fmt.Println(j.SayAge())
    // オーバーライドされていること
    fmt.Println(j.SayName())
}
実行結果
20です。
初めましてMikeです。

Human,JapaneseにSayName関数を実装してオーバーライドされるか、親クラスの関数の呼び出しが可能か確認しました。
実行結果の通り親クラスの関数の呼び出し、オーバーライドが行えていることがわかります。
Embeddedにより、オブジェクト指向の特徴である。継承、ポリモーフィズムといった機能が実装できることがわかります。

基本文法

パッケージ

Goではプログラムをpackageごとに分割しています。
importすることで他パッケージの利用もできます。
Goでは大文字で始まるものがPublic、この字で始まるものがPrivateとされるため、大文字始まりの定数や関数を呼び出すことができます。

package main

import (
    "fmt"
    "strconv"
)

func main() {
    fmt.Println("Hello!");
}

function(ファンクション):関数

Goではファンクションに処理を書きます。Javaでいうメソッドです。
大文字であればPublic、小文字であればPrivateで利用できます。
以下のように定義されます。

func  <関数名>([引数]) [戻り値の型] {
    [関数の本体]
}
func (j Japanese) SayName() string {
    return "初めまして" + j.name + "です。"
}

func New(name string, age int, weight int) *Japanese {
    return &Japanese{Human{name, age}, weight}
}

先ほど継承の例で挙げた例を参考にすると、
SayNameメソッドはJapanese構造体に付随されており、引数はなし、戻り値はstringとされています。
Newメソッドは引数はname、age、weightとされ、Japanese構造体のポインタを返却しています。
※構造体とポインタはのちにて説明します

変数・定数

変数はvar、定数はconstにより定義します。
これに関してもPublic、Privateは大文字小文字で決まります。
宣言時は変数名、型の順で記述します。直接文字列、数値を入れる場合は型定義の必要がありません。
変数に値を代入したい場合は:=を利用することで宣言記述を省略できます。
定数の場合は:=を利用できません
定数で宣言できるのはstringboolcharacternumericのみです。

var name1 string
var name2 = "Mike"

const age1 int
const age2 = 1

func main() {
    name3 := "Jessica"
}

for/if/Switch

Switch/if条件/forループは()で囲む必要がなく記載ができる。{}の括りは必要。
Switch文はJavaではbreakでswitch文を抜けますがGo言語ではbreakは不要です。
Switch文はfallthroughを利用することでcase文で

func main() {
    sum := 0
    for i := 0;i < 10;i++ {
        sum += 1;
        if sum<5 {
            fmt.Println("合計値が5以上")
        }
    }
    result := judge()
}

func judge() string {
    switch sum
    case sum == 5:
        return "合計値が正しくないよ"
    case sum == 10:
        return "合計値が正しいよ"
    default:
        return "想定値以外"
}

struct(ストラクト):構造体

Goでは構造体にそのパッケージで利用する変数を定義します。
Javaでいうクラスに当たります。継承の記述説明を行った時同様に、処理を持たせることもできます。
type 構造体名 struct {}で宣言することができます。フィールド変数を呼び出すときは構造体名.変数名にて利用することができます。
ストラクトの初期化には「直接変数に値を入れる」「ストラクトの記載順で値を入れる」「フィールド名を指定して値を入れる」の3パターンがあります。

type Human struct {
    name string
    age  int
}

func (h Human) SayName() string {
    return h.name + "です。"
}


func New(name string, age int) *Human {
    // ストラクトの順に値を入れる
    return &Human{name, age}
}

func main() {
    // 初期化 
    h := New("Mike", 20)
    // Humanストラクトの変数呼び出し
    fmt.Println(h.name)
    // Humanストラクトの処理呼び出し
    fmt.Println(h.SayAge())

    // フィールド名指定で初期化する
    Alex := Human{name: "Alex", age: 10};
    // ストラクトに直接値を入れる
    Alex.age = 20
}

point(ポインタ):メモリアドレス

ポインタはメモリのアドレス情報のことです。
GO言語では&を変数、構造体の前につけることでアドレスの取得(ポインタの取得)ができます。
また、*を変数名の前に記述することでポインタ型で変数宣言が可能です。
ポインタの存在意義が分からない場合はこちらの記事を参考にしてください
Goで学ぶポインタとアドレス

type Human struct {
    name string
    age  int
}

func main() {
    // Human型で宣言
    h1 := Human{"Mike", 20}
    fmt.Println(h1)
    // Human型の別ストラクトの宣言
    h2 := h1
    h2.name = "Alex"
    fmt.Println(h2)
    fmt.Println(h1)
    // ポインタ型で宣言
    h3 := &h1
    h3.name = "Alex"
    fmt.Println(h3)
    fmt.Println(h1)
}
実行結果
{Mike 20}
{Alex 20}
{Mike 20}
&{Alex 20}
{Alex 20}

Human型で宣言した場合はh2には代入できているが、h1に反映できていない。これを値渡しという。
ポインタ型で宣言した場合は大元のHuman型で宣言した値に対して代入されていることがわかる。これを参照渡しという。

配列

配列とは、同じ型を持つ値(要素)を並べたものです。
複数の宣言方法があります。
最初に宣言した配列のサイズを変えることはできません。

宣言方法
var 変数名 [長さ]型
var 変数名 [長さ]型 = [大きさ]型{初期値1, 初期値n} 
変数名 := [...]型{初期値1, 初期値n}
// 宣言方法1
var Names1 [2]string

// 宣言方法2
var Names2 [2]string = [2]string{"Mike", "Alex"}

// 宣言方法3
var Names3 = [...]string{"Mike", "Alex"}

func main() {
    // 値の取得
    fmt.Println(Names2[0])
    fmt.Println(Names2[1])
    fmt.Println(Names1, Names2, Names3)
}
実行結果
Mike
Alex
[ ] [Mike Alex] [Mike Alex]

slice(スライス):要素指定が必要ない配列

配列とは異なり長さ指定の必要がない。
別の配列から要素を取り出し参照する形での宣言やmake()を利用した宣言が可能。宣言時に値を入れることはできない。make(型,長さ,容量)で宣言が可能です。容量は省略が可能で、省略した場合長さと同じ値とされます。
配列とは異なり要素の追加が可能です(append)。
数値の意味合いは以下のようになります。

操作 意味
Slice[start:end] start から end - 1 まで
Slice[start:] start から最後尾まで
Slice[:end] 先頭から end - 1 まで
Slice[:] 先頭から最後尾まで

長さ(length)と容量(capacity)の両方を持っています。
型が一致している場合、他のスライスに代入することが可能です。
スライスのゼロ値はnil。

宣言方法
var 変数名 []型
var 変数名 = make([]型,2,2)
    var arr [2]string = [2]string{"Mike", "Alex"}

    var slice1 []string
    var slice2 []string = []string{"Mike", "Alex", "jessica"}

    // 配列からの代入
    var slice3 []string = arr[0:2]

    // makeを使用した宣言
    // make(型,長さ,容量)スライスオブジェクトの確保、初期化を行う。容量は省略可能
    var slice4 = make([]string, 2, 4)

    // appendによる追加
    var slice5 []string = []string{"Mike", "Alex"}
    slice5 = append(slice5, "jessica")

    fmt.Println(slice1, slice2, slice3, slice4, slice5)
    fmt.Println(len(slice2), cap(slice2))
実行結果
[] [Mike Alex jessica] [Mike Alex] [ ] [Mike Alex jessica]
3 3

次の記事

GO言語基礎②(defer/map/range/Interface/goroutine/channel)

参考記事

go言語 メリットとデメリット
JavaプログラマーのためのGo言語入門
Go言語でハマったことメモ(クラス・継承)
【Go】基本文法総まとめ

1
1
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
1
1