Go

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動
メインページ > 工学 > 情報技術 > プログラミング > Go

Go言語は、グーグルの開発したプログラム言語のひとつです。 主にGo言語はサーバ用途で用いられます。Go言語はオープンソース化されており、フリーです。

なお検索の都合などで「golang」などと表記される場合もありますが、このプログラム言語の正式名称は「Go」です。本書では説明の都合上、「Go言語」などとも呼ぶことにします(日本のIT業界でも一般的に受け入れられてい呼び方です)。

目次[編集]

入門
関数とメソッド
  • Go/関数
  • Go/メソッドとインターフェース
データ構造
その他


※ 以下、未分類[編集]

※ 下記の記述は、もし、ある程度の量の記述がまとまったら、それからサブページを作成して、そのサブページに記述を移動してください。

編集の手順としては、さきに記述がある程度の完成をしてから、あとからサブページを作成することを、オススメします。


文字入力の方法[編集]

キーボードから文字列の入力を受け付ける方法は、Go言語では、C言語風の方法と、Java風の方法との、少なくとも2種類の方法が用意されている。

C言語風の方法[編集]

コード例
package main

import (
    "fmt"
)

func main() {
    fmt.Println("文字列をなにか入力してください")
    
    var moji string
    fmt.Scan(&moji)

    fmt.Printf("あなたは %s と入力しました。",moji )

}


実行例
文字列をなにか入力してください
ghf
あなたは ghf と入力しました。


解説

C言語のscanf()関数が、ほぼ似た仕組みである。(というか、おそらく、GoのScanの元ネタがscanfであろう。

(※ C言語のscanf()について詳しくは C言語/基礎知識#scanf関数を参照せよ)


Java風の方法[編集]

コード例
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    fmt.Println("文字列をなにか入力してください")
    
    hensu := bufio.NewScanner(os.Stdin)
    hensu.Scan()

    fmt.Printf("あなたは %s と入力しました。",hensu.Text() )

}


実行例
文字列をなにか入力してください
ghf
あなたは ghf と入力しました。


解説

ずいぶんと面倒であるが、これはおそらくJavaの文字入力の文法をマネていると思われる。

hensu 以外のbufio や NewScanner など、すべて予約語である。

Go言語は理念としては、本来なら Java の置き換えや連携などは狙っていないのだが(Java との連動をしている理念の言語は(Goではなく) Kotlin である)、なぜかGo言語は文法が所どころ、Javaに似ているのである。


上記コードは、なにをしているかと言うと、おおむね

キーボード入力のできるオブジェクトを呼び出してメモリ領域などを確保し、 (※ hensu := bufio.NewScanner(os.Stdin) あたり)
そのオブジェクトをキーボード入力受け付けのモードに設定している、 (※ hensu.Scan() あたり)

のような流れである。


ちなみにJava の場合、コンソール入力の方法は、

// これは Java 用です。Go用でもなくkotlin用でもないので注意!

Scanner hensuu = new Scanner(System.in); 
String hensuu = hensuu.nextLine();

のようにscanner 型を使ってオブジェクトを用意して、メモリ確保のために変数を宣言し(上記コードの Scanner hensuu の部分 )、さらにその変数に nextline プロパティなどを設定するという仕組みである。

メソッドとインターフェース[編集]

メソッド[編集]

JavaScriptなどに

オブジェクト.メソッド()

のように特定の「オブジェクト」なるものに所属する関数としてメソッドというものがあります。

Go言語では、type演算子などを使って、このようなメソッドを作成できます。

メソッドの書式については文章だけで説明しても難しいので、まず先にコード例を提示します。(後述で書式などを説明します。)

コード例
package main

import (
	"fmt"
)

type kou int // 型を定義

func (n kou) tasugo() kou {
    // 5を足すだけの処理
    return 5 + n
}

func main() {
	var n kou
	var m kou
	n = 7
	m = n.tasugo()
	fmt.Printf("%d\n", m)

}
実行結果
12
(※ 5+7=12なので)


上記コードの書式を解説すると、下記のようになります。

上記コード例の書式など
package main

import (
	"fmt"
)

type 型名 

func (レシーバ変数 型名) メソッド名() 型名 {
	return 戻り値
}

func main() {
	var n kou
	var m kou
    
    // 初期値など
    n = 7
	m = レシーバ変数.メソッド()

    fmt.Printf("%d\n", m)
}

読者には

type 型名 型

というのが冗長に思えるかもしれませんが、しかしGo言語の仕様により、(関数ではなく)メソッドを使う際には、こう書かないと、エラーになります。(たぶん、コンパイラ作成時のいろいろな事情がありますので、気にせず、「こう書くのだ」と覚えてください。)一方、メソッドではなく関数を使うだけなら、このtypeの文は不要です。


さて、最後のほうで「fmt.Printf("%d\n", m)」とありましが、もし、ここを

fmt.Printf("%d\n", n.nibai() )

のように一度にまとめて書いても、エラーになります。

なので、

   m = n.nibai()
   fmt.Printf("%d\n", m)

のように、組み込み関数の外で、メソッドの値を、べつの変数に代入する必要があります。(よそのプログラム言語でも、似たような現象があり、こういう作業を「インスタンス」という。メモリの確保などのコンパイラ内部などの都合により、あらかじめ別の変数に代入するなどの必要がある。)


レシーバ変数
func (n kou) tasugo() kou {

において、funcの直後の ( ) のなかの変数をレシーバ変数と言います。

つまり、書式は

func (レシーバ変数 型名) メソッド名() 型名 {

です。

本節の冒頭のコード例

func (n kou) tasugo() kou {

では、「n」がレシーバ変数です。


メソッドを呼び出すときの書式は、

レシーバ変数.メソッド()

の書式です。

そして、これを「インスタンス」(メモリ確保などのための事前処理)のために、別の変数(たとえばmなど)に代入する必要があるわけですから、

m = レシーバ変数.メソッド()

みたいな記述がコード中のどこかにあるコーディングをする事になるでしょう。

インターフェース[編集]

※ 未記述

ネットワーク関係[編集]

いわゆる普通のwebサイトの形式である、HTML形式のwebサイトのプロトコルは「HTTP」というプロトコルである。

で、そのHTTPサーバを建てる場合、localhostでいいなら

サーバ側のコード例
package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", aaa)
    http.ListenAndServe("localhost:8080", nil)
}


func aaa(qq http.ResponseWriter, ttt *http.Request) {

fmt.Fprintf(qq,"<h1>あいうえお</h1>\n" )

}

でサーバが建つ。


上記コード中の「aaa」とか「qq」とか「ttt」はデタラメにつけた名前なので、この部分は他の名前でもいい。


webブラウザでアドレス「localhost:8000」にアクセスし、拡大表示された「あいうえお」が表示されていれば成功。


なお、

Fprintf

とは、ファイル入出力の読み書きの関数。Go言語は、このファイル入出力の関数を、HTTP通信にも流用している。(なおPHPも、記述方法は違うが、ファイル入出力の機能を流用する方式である。)


これらの処理でGo言語が一体なにをやっているかというと、ソケット通信というのをやっている。(詳しくは『WinSock』または『Unixソケットプログラミング』を参照せよ。)


上記コードでは「aaa」とかデタラメに変数名をつけたが、慣習的には下記コードのような変数名になる。

サーバ側のコード例
package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", aaa)
    http.ListenAndServe("localhost:8080", nil)
}


func aaa(w http.ResponseWriter, r *http.Request) {

fmt.Fprintf(w,"<h1>あいうえお</h1>\n" )

}

「w」とか「r」とか何かよく分からないが、慣習的にこう書くので、その慣習に合わせておこう。


ファイル入出力[編集]

実行しているプログラムファイル以外の外部ファイルを読み込んだり、外部ファイルを作成したり、外部ファイルに書き込んだりすることを「ファイル入出力」と言います。

Go言語では "os" パッケージをインポートしないと、ファイル入出力できないです。

osパッケージの組み込み関数である os.Create 関数で、外部ファイルを作成できます。

os.Create 関数を使用する際、この関数は戻り値を2つ使用します。むりやりに戻り値を1つだけでコードを書いてもエラーになります。


os.Create 関数の第1引数は、正常動作時の戻り値、第2引数はエラー時に書き込まれる戻り値であると、Go言語の仕様が決まっています。


下記コードでは、わかりやすさを重視するため、ファイルのオープンのエラー時の処理を省略しています。

「nil」とは、よその言語でいう「ヌル」みたいなもので、データの空いている状態をあらわすモノです。

下記コードではエラーが起きた場合、変数 kensa はos.Createによって書き込まれるので、もはや空白ではなくなるので、

if kensa != nil {

となっているのです。関係演算子の「 != 」とは「でなければ」という意味です。


コード例
package main

import (
	//"fmt"
	"os"
)

func main() {
	namae := "ftes.txt"
	
	var nanka *os.File
	var kensa error
	
	nanka, kensa = os.Create(namae)
	
	if kensa != nil {
	    // ひとまずダミー
	}
	
	mojiretu := []byte("書き込みテストhj4")
	nanka.Write(mojiretu)
	 
}


実行の結果
「ftes.txt」という名前のファイルが作成されているハズ。
そもファイル「ftes.txt」を開いて閲覧すると、「サンプル」と書かれている。


*os.File

のosの前についている記号はアスタリスクです。


text1 := []byte("書き込みテスト4")

[]byteは、そういう予約語みたいなものです(スライス関連)。慣用句として、そのまま覚えたほうが早いです。


上記コードでは、予約語以外の部分を「namae」(名前)とか「nanka」(何か)とか「kensa」(検査)とかにしましたが、

実際のコードでは慣用的に英語で機能に近い意味の名称が使われます。

コード例
package main

import (
	//"fmt"
	"os"
)

func main() {
	fname := "ftes.txt"
	
	var file *os.File
	var err error
	
	file, err = os.Create(fname)
	
	if err != nil {
	    // ひとまずダミー
	}
	
	txt := []byte("書き込みテスト3")
	file.Write(txt)
    
    file.Close()
}


os.Create() 関数や os.Open() 関数によって開かれたファイルは、 Close() によって閉じることができます。閉じられたファイルは、再度 開くまでは、読み書きができない状態になっています。

間違えてデータを壊すことを防ぐ安全のため、なるべくファイルは使い終わったら、すぐに閉じるのが無難です。


Go言語の関数は、2個以上の値を返却できる。こういう風に、1つの関数が複数の値を返却できる仕組みを多値返却という。

ほかのプログラム言語でも、PerlPythonの関数も、あまり話題にならないが、実はそれらの言語の関数は多値返却も出来る。


余談

2019年、エラー処理について、文法の改訂案が出された。

その提案は、エラー時のif文を毎回書くのは非効率なので、C++でいう try catch 構文のようなエラー処理のための例外処理の文法を搭載しようという案である。

だが、2019年、一度、この案は棄却された。Go1.14では採用がいったんは棄却されたが、引き続き、なんらかの改善は必要性があるとして、今後のバージョンでは注目が必要である。

なお、2020年現在、まだGoの最新版のバージョン番号は Go1.14 台である。