WEB

May 22, 2020

Go
初心者

Goプログラミング言語のチュートリアル 〜 基礎的な文法・Part1

post 40

最近のWEB開発ではGo言語の採用が増えているので、こちらの書籍で基本に触れてみた。


本書では以下のように一通りの言語仕様が解説されている。

■ Chapter1 - Go言語による開発の概要 ★
■ Chapter2 - Go言語の基本 ★
■ Chapter3 - 関数とメソッド ★
■ Chapter4 - 構造体 ★
■ Chapter5 - インタフェース
■ Chapter6 - 配列・スライス・マップ
■ Chapter7 - エラーハンドリング
■ Chapter8 - 並列処理
■ Chapter9 - 逆引きリファレンス

本記事では★印の4分野に絞って確認。

コンパイルと実行

コンパイルは、Go言語インストールディレクトリ中のbinに格納されている goツール を使用。

go build -o 実行ファイル名 ソースファイル名

コンパイルと同時実行する場合、以下のコマンドを実行。

go run ソースファイル名

ただし上記コマンドでは、実行ファイルは残らない。

インポート

インポート宣言を行った場合、必ず何かしらインポート対象のパッケージ識別子にアクセスの必要がある。インポートしたのに、一度も使用しないとコンパイルエラーとなってしまう。

package main

import "fmt"

func main() {
}

[実行結果] ./prog.go:3:8: imported and not used: "fmt"

またインポートによる副次的処理(DB接続のような自動処理される初期化処理)のため、パッケージをインポートする必要があるケースでは ブランク識別子 で対応。

import (
	"net/http"
	_ "github.com/mattn/go-sqlite3"
)

エクスポート

エクスポート は、識別子にパッケージ外からアクセスを許可すること。

package main

const Export = true  // 先頭が大文字なので、エクスポートされる
const export = false // 先頭が小文字なので、エクスポートされない

func main() {
	const Z = 123    // 先頭は大文字だが、ローカル変数のためエクスポートされない
}

また識別子の先頭文字を大文字にすることで、外部パッケージからのアクセスが可能となる。

文字列

文字列string型 で定義。

var val1 = "test1"
fmt.Println(val1) // test1

シングルクォーテーションでは ルーンリテラル(Unicodeコードポイント) で定義される。

var val = 'a'
fmt.Println(val) // 97

len はバイト数。文字数カウントは、unicode/utf8パッケージの RuneCountInString を利用。

package main

import "fmt"
import "unicode/utf8"

func main() {

	var ja string = "Go言語"
	fmt.Println(ja, "len:", len(ja)) // Go言語 len: 8
	fmt.Println(ja, "len:", utf8.RuneCountInString(ja)) // Go言語 len: 4
}

変数と定数

変数定義 では var を利用する。

// var 変数名 型
var x int = 10

// [省略系] 変数名 := 初期値
y := 123

定数定義 では const を利用する。

// const 定数名 型
const x int = 10

ポインタ

基本的な文法では ポインタ が気になったので利用方法を確認。

package main

import "fmt"

func main() {
	var ptr *int
	var i int = 12345
	ptr = &i
	fmt.Println(ptr) 
}

ある変数を関数に渡すと、実際の値はコピーされる。そのため関数内で値を変更しても、元の値に影響はないが、値のポインタを関数に渡すと、元の変数の値を書き換えることは可能となる。

関数

関数宣言の書式は以下のとおり。

func 関数名(パラメータリスト) 戻り値の型 {
	// 処理
	return 戻り値
}

戻り値に名前を付けることで、パラメータの記述なしにreturnが可能。

package main

import "fmt"

func calc(a int, b int)(add int, sub int, mul int, div float32) {
	add = a + b
	sub = a - b
	mul = a * b
	div = float32(a) / float32(b)	
	return
}


func main() {
	add, sub, mul, div := calc(10, 2)
	fmt.Println(add, sub, mul, div)
}

[実行結果] 12 8 20 5

メソッド

関数とメソッドの違いは レシーバ を記述するかどうか。

package main

import "fmt"

type myType int

// func (レシーバの変数名 レシーバの型) メソッド名(引数) {}
func (value myType) println() {
	fmt.Println(value)
}

func main() {
	var z myType = 1234
	z.println() // 実行結果:1234
}

レシーバで指定する型は、同一パッケージ内で宣言する必要があり、レシーバを持つ変数経由で値へのアクセスが可能(インタフェース型はレシーバに指定出来ない)

またメソッド内で値を変更する場合は、レシーバの型の前に*を記述して、ポインタにする必要がある。

package main

import "fmt"

type myType int

func (value *myType) setByPointer(newValue myType) {
	*value = newValue
}

func main() {
	var x myType = 0
	x.setByPointer(1)
	fmt.Println(x) // 実行結果:1
}

最初からポインタ型である型を利用出来ない。

構造体

フィールドと呼ばれる要素を持つ集合体で、フィールドは名前と型を持つ。

type 構造体名 struct {
	UserId string
	Name   string
	Email  string
}

他の識別子と同様、先頭1文字を大文字にするとエクスポートされる(外部パッケージから参照可能)


©Copyright2020 TaNA LABO. All Rights Reserved.