赶紧学习Golang
关于
这是为那些有其他语言经验的人和想要学习Golang的人提供的一个快速学习基本语法的总结。
你好,世界
首先是基本的“你好世界”。
package main
import "fmt"
func main() {
fmt.Println("Hello, World")
}
Go Playground
把以下内容用汉语进行本地化解释,只需要一个选项:
包裹
所有的非main包必须与目录结构一致。
软件包声明
package pkg
导入
引入包(package)的导入
import "pkg"
也可以同时导入多个包。可以使用“标准包”,“工作空间上的包”和“本地(相对路径)”来导入。
import (
"pkg"
"pkg/sub"
a "abc" // 別名でのimport
. "def" // ドットでのimport(package名を省略できる
_ "ghi" // ブランクでのimport(init関数だけ実行され, packageは使用できない)
)
导出
在顶级声明的情况下,可从其他包中使用“函数/方法”、“变量/常量”和“类型”。然而,它们需要以大写字母开头。
type Hoge struct {
Name string // public扱い
age int // private扱い
}
func Hello() {
fmt.Println("public扱い外部から使用できる")
}
func hello() {
fmt.Println("private扱い外部から使用できない")
}
初始化函数
用于执行一次的特殊函数,用于初始化package(在程序执行时首先被调用)。它可以有多个定义但调用顺序是不确定的。
func init() {
fmt.Println("init1")
}
func init() {
fmt.Println("init2")
}
内部
供应商
基础语法
评论 tǐ)
// 行コメント
/*
ブロックコメント
*/
行末
基本上,將換行視為行尾處理。即使是「;(分號)」也是行尾。
var v1 = 1
var v2 =
2
鉴别符号
用中文进行翻译的一种方式如下:
与基本的编程语言相同的([a-zA-Z_][a-zA-Z_0-9]*). 为了防止错误,明确规定不使用一个下划线的特殊(空白)标识符。
var _ = 100
v, _ := Func() // 2個目の戻り値は使わない
– 类型
基本型 – 原生地在中文中改述 。
多功能的
变量声明
谷歌的Go语言的变量声明
-
- 型名が変数名のあと(var 変数名 型名)
-
- varキーワードを使う(:=で省略可能)
- 型推論できる
var v1 int // 初期値なし(デフォルト値で初期化)
var v2 int = 10 // 初期値あり
var v3 = 10 // 型の省略(初期値の指定の必要あり)
var v4, v5 int // 複数の変数(初期値なし)
var v6, v7 int = 10, 20 // 複数の変数(初期値あり)
var v8, v9 = 10, 20 // 複数の変数(型省略)
var v10, v11 = func() // 戻り値が2個の関数
var ( // まとめて宣言
v12 int = 100
v13 = 200
)
v14 := 300 // var v14 = 300と同じ
文字
// 整数リテラル(int型)
dec := 1234
oct := 01234
hex := 0xabc
// 浮動小数点リテラル(float64型)
f1 := 1.2
f2 := 1.2e-2 // 指数表記
// 虚数リテラル(complex128型)
i1 := 1.2i
i2 := 1.2i+3
i3 := complex(1.2, 2.3) // 組み込み関数complexで複素数を作成
real(i3) // 組み込み関数realで実数部を取得
imag(i3) // 組み込み関数imagで虚数部を取得
// 文字
r := 'a' // rune(Unicodeコードポイント)文字
s := "abcdefg" // 文字列
raw := `abcd
efg` // raw(生)文字列
// 複合リテラル
v1 := [3]int {1,2,3} // 配列
v2 := []int {1,2,3} // スライス
v3 := map[string]int {"a":1} // マップ
v4 := struct{ a int} {a: 1} // 構造体
// 関数リテラル
f := func(a int) int {return a}
f(3)
固定的数量
const (
c1 uint = 1 // uint型
c2 = c1 // uint型
c3 = 3 // 型なし
)
const (
u1 uint = 1 // 1
u2 = 1 // 1
u3 = 1 // 1
)
忽略微小的东西。
可以创建类似于enum的连续值常量。
package main
import (
"fmt"
)
const (
a0 = iota // 0
a1 = iota // 1
a2 = 10 // 10
a3 = iota // 3(iotaの値は()内での行数で決まる)
a4, a5 = iota, iota // どちらも4
)
const (
b0 = iota // 0
b1 // 1(省略可能. 1行目のiota式を使用)
b2 // 2(〃)
_ // 3(ブランクによるスキップ
b3 // 4
b4 = iota * iota // 25(5*5)
)
const (
c0 = 1 << iota // 1(1 << 0)
c1 // 2(1 << 1)
c2 // 4(1 << 2)
c3 // 8(1 << 3)
)
func main() {
fmt.Println(a0, a1, a2, a3, a4, a5)
fmt.Println(b0, b1, b2, b3, b4)
fmt.Println(c0, c1, c2, c3)
}
Go Playground
演员阵容
v1 := int64(100) // int->int64
s1 := []byte("abc") // string->[]byte
s2 := string(s1) // []byte->string
条件分岐,也称为if语句。
Golang的if语句
-
- ()で条件式を囲わない
-
- 条件式は真偽値型でなくてよい
-
- else if/elseは前の条件ブロック{}の後に書く. 改行しない
- if文(elseブロックの最後まで)だけのスコープを持つ変数を宣言できる(他の制御構文も同様)
if 条件式1 {
// 条件式1がtrueのとき実行
} else if 条件式2 {
// 条件式2がtrueのとき実行
} else {
// それ以外のとき実行
}
// if文での変数宣言
// 初期化文で使える文
// 変数宣言(:=), 代入文, ++, --, 関数, メソッド呼び出し, チャンネル送信・受信
if 初期化文; 条件式1 {
...
} else if 初期化文; 条件式2 {
...
} else {
...
} // スコープはここまで
条件分岐(switch语句)
Golang的switch语句
-
- break文を書かなくても次のcaseが実行されない(実行するにはfallthrough文を使う)
- case文に条件式を書くこともできる(trueの場合実行)
switch 式1 {
case 式2:
...
case 式3, 式4:
// 式3と式4のいずれかと一致した場合実行
...
case 式5:
...
// 次のcaseも実行される
fallthrough
case 式6:
...
default:
...
}
switch { // ここには式を書かない
case 条件式1:
...
case 条件式2:
...
default:
...
}
Go Playground
循环(for循环)
Golang的for循环
-
- 繰り返しはfor文だけ(while文/do while文はない)
-
- 基本はC言語などと同じ
-
- 多重for文はラベル指定のbreak文/continue文で抜ける(goto文でも可能)
- 拡張for文(foreach)は組み込み関数rangeを使う
for 初期化文; 条件式; 更新処理文 {
...
}
// 条件式のみ(while)
for 条件式 {
...
}
// 無限ループ
for {
...
}
// ラベルで外部ループにジャンプ
Loop:
for ... {
for ... {
if ... {
continue Loop
}
if ... {
break Loop
}
}
}
package main
import (
"fmt"
)
func main() {
// 文字列
// 第1変数:バイト単位の位置
// 第2変数:rune(Unicodeコードポイント)
s := "hoge"
for i, c := range(s) {
fmt.Println(i, string(c)) // rune->string
}
// 配列・スライス
// 第1変数:インデックス
// 第2変数:要素
a := []int {1,3,5}
for i, v := range(a) {
fmt.Println(i, v)
}
// マップ
// 第1引数:キー
// 第2引数:バリュー
m := map[string]int {"a":1, "b":2, "c":3}
for k, v := range(m) {
fmt.Println(k, v)
}
// チャネル
// 第1引数:受信した値
// 第2引数:なし
ch := make(chan int)
go func() {ch<- 10}()
for v := range(ch) {
fmt.Println(v)
}
}
Go游乐场
函数
Golang的函数
-
- funcキーワードを使う
-
- 2個まで返すことできる
-
- 戻り値に名前を付けることができる
- 関数終了時に呼び出す関数を登録するdefer文
// 引数・戻り値なし
func Fn1() {
...
}
// 引数あり
func Fn2(s string, b int) {
...
}
// 同じ型ならまとめられる
func Fn3(a, b int) {
...
}
// 可変長引数
func Fn4(s ...string) {
...
}
// 戻り値1個
func Fn5() int {
return 1
}
// 戻り値2個
func Fn6() (int, int) {
return 1, 2
}
// 名前付き関数
func Fn7() (v int) {
...
return // 自動的に名前付きの変数が返される
...
return 10 // 値をしてした場合, 指定した値が優先される
}
// defer文
// 関数はスタックに格納される(LIFO. 最後のdefer文が先に実行される)
// 関数終了時に実行するべき関数を登録しておく
func Fn8() {
defer f(1)
defer f(2)
defer f(3)
}
形态宣言
声明Golang的类型
-
- typedefに相当する
-
- 基本型・複合型から新しい型を作成する
-
- 元の型<->新しい型(代入可能・型変換可能)
- 同じ基底型を持つ型同士(代入不可・型変換可能)
// type 新しい型 元の型
type myInt int
type myAry [10]int
结构体
Go语言的结构体
-
- 継承はできない
-
- 匿名フィールドに構造体を埋め込むことはできる
- 各フィールドにタグ情報を埋め込める(xml,jsonのパースなどに使える)
package main
import (
"fmt"
)
type Person struct {
Name string
Age int `key:"value"` // タグ情報
}
type Worker struct {
Person // 匿名フィールド
Work string
}
func main() {
var p1 Person
p1.Name = "aiueo"
p1.Age = 20
p2 := Person{Name: "abcde", Age: 40}
p3 := Worker{p2, "NEET"}
fmt.Printf("%#v\n", p1)
fmt.Printf("%#v\n", p2)
fmt.Printf("%#v\n", p3)
}
Go Playground
指针
Golang的指针
-
- 基本はC言語などと同様
-
- &(アドレス参照演算子), *(間接参照演算子)を使う
-
- 組み込み関数new(型)でメモリを確保する
-
- 参照先のないポインタはnullではなくnil
GC(ガベージコレクション)で自動的にメモリは開放される
危険なポインタアクセスはできない(unsafeパッケージで扱える)
package main
import (
"fmt"
)
func main() {
v := 10
p := new(int)
*p = 100
p1 := &v
fmt.Println(*p)
fmt.Println(*p1)
}
Go Playground
方法
使用Go编写的方法
-
- typeで作成した型に関数(メソッド)を持たせることができる
- 値レシーバ・ポインタレシーバ
package main
import (
"fmt"
)
type Int int
type St struct {
x int
}
func (v Int) add(n int) Int {
return v + Int(n)
}
func (st *St) add(n int) {
st.x += n
}
func main() {
v1 := Int(10)
v1 = v1.add(5)
fmt.Println(v1)
st := St{x:20}
st.add(5)
fmt.Println(st)
}
Go playground 在线编程调试器
界面
Go语言的接口
-
- メソッドの集合
-
- インターフェースを実装するにはすべてのメソッドを実装する
-
- 構造体と同様に匿名フィールドにインターフェースを埋め込むことはできる
-
- interface{}はすべての型の値が代入可能
-
- interface型の「==」演算子は同じ型かつ同じ値のときのみtrueを返す
nilは型なしのnilとのみ一致する. 型がある場合はそれぞれのポインタ型のnilと一致する
元の型に戻すには型アサーションを使う(第1戻り値に変換した値, 第2戻り値に真偽値)
型switch文で型ごとの処理ができる
package main
import (
"fmt"
)
type IAnimal interface {
Name() string
Cry() string
}
type Cat struct {
name string
}
type Dog struct {
name string
}
func (a Cat) Name() string {
return a.name
}
func (a Cat) Cry() string {
return "にゃん"
}
func (a Dog) Name() string {
return a.name
}
func (a Dog) Cry() string {
return "わん"
}
func main() {
var a IAnimal
a = Cat{"みけ"}
fmt.Println(a.Name(), a.Cry())
a = Dog{"ぽち"}
fmt.Println(a.Name(), a.Cry())
var n interface{} // なんでも代入できる
n = 10
n = "abc"
fmt.Println(n)
}
Go语言的游乐场
package main
import (
"fmt"
)
func main() {
var i0 interface{} = 10
var i1 interface{} = "a"
var i2 interface{} = 10
var v0 int = 20
var v1 string = "b"
fmt.Println(i0 == i1) // false(型だけの一致)
fmt.Println(i0 == v0) // false(値だけの一致)
fmt.Println(i1 == v1) // false(両方の不一致)
fmt.Println(i0 == i2) // true(両方の一致)
// 元の型に戻すことで代入可能
v0, ok := i0.(int)
if ok {
fmt.Println("int変換成功", v0)
}
v1, ok = i1.(string)
if ok {
fmt.Println("string変換成功", v1)
}
switch v2 := i1.(type) {
case int:
fmt.Println("int", v2)
case string:
fmt.Println("string", v2)
case float32, float64:
fmt.Println("float", v2)
}
}
Go 乐园
数组、切片、映射
Golang的数组和切片
-
- []を型名の前に書く
-
- 固定長を配列, 可変長をスライス
-
- 配列は値型, スライスは参照型
-
- 組み込み関数appendで拡張可能(容量が不足なら再割当てされる)
-
- 組み込み関数makeでメモリ確保
-
- 組み込み関数len, capで長さ, 容量を取得
-
- 組み込み関数copyでスライスをコピー(コピー先の長さまでがコピー元の要素で上書きされる)
-
- スライス式でスライスの一部を取り出し(0<=start<=end<=len, 新しいスライスの容量はlen-start)
- フルスライス式で取り出す容量を制限(0<=start<=end<=max<=len, 新しいスライスの容量はmax-start)
用Go语言的映射数据结构。
-
- マップの型はmap[キーの型]要素の型
-
- マップ[キー]で参照(第1戻り値が要素またはデフォルト値, 第2戻り値に真偽値)
- 組み込み関数makeで要素数を指定した方が高速
数组(固定长度)
ary1 := [3]int{11, 12} // 長さ指定([2]はデフォルト値)
ary2 := [...]int{21, 22, 23} // 長さ指定なし
ary3 := [3]int{0: 31, 2:32} // インデックス指定
length := len(ary1) // 長さの取得
切片(可变长)
slice1 []int // nil
slice2 []int{11,12,13} // 長さ2
slice3 []int{21,22,23} // 長さ3
append(slice2, 14, 15, ...) // 要素を追加(可変長引数)
append(slice1, slice3...) // スライスを追加
slice4 := make([]int, 5) // 長さ5(容量5)のスライスを確保(デフォルト値を設定)
slice5 := make([]int, 5, 10) // 長さ5・容量10のスライスを確保(デフォルト値を設定)
capacity := cap(slice5) // 容量の取得
copy(slice5, slice2) // slice5(長さ5)にslice2の要素が5つまで上書きコピー
slice6 := slice5[1:3] // [1]-[3-1]
slice7 := slice5[2:] // [2]-[len-1](最後)
slice8 := slice5[:2: // [0](最初)-[2-1]
slice9 := slice5[:] // [0](最初)-[len-1](最後)(コピー)
slice10 := slice5[1:3:5] // [1]-[3-1]を容量(5-1)
地图
map1 := map[string]int{"a":1, "b":2, "c":3}
k, v := map1["key"]
if v {
fmt.Println(k)
} else {
fmt.println("キーが存在しない")
}
map2 := make(map[string]int) // 要素数の指定なし
map3 := make(map[string]int, 10) // 要素数の指定あり
错误
-
- errorインターフェス
- panic
同时处理(协程)
-
- 標準で並列処理ができる
goを関数に付けて呼び出すと別ルーチンで実行
通信用のチャネル型変数を使う
バッファなしチャネルは同期通信, バッファ付きチャネルは非同期通信(容量まで貯める)
組み込み関数closeでチャネルを閉じると受信以外できなくなる(クローズされている場合, 第1戻り値にデフォルト値, 第2戻り値に真偽値)
for rangeはチャネルがクローズされるまで繰り返す
select文を使うことで複数のチャネルを扱うとき送信待ち・受信待ちで他の操作ができなくなるのを防ぐ
chan int // 送受信可能なチャネル型
chan<- int // 送信のみ可能なチャネル型
<-chan int // 受信のみ可能なチャネル型
make(chan int) // バッファなしチャネル
make(chan int, 5) // バッファ付きチャネル
ch <- 10 // チャネル送信文
<-ch // チャネル受信
close(ch)
n, t := <-ch
if t {
fmt.Println(n)
}
// クローズするまで繰り返す
for n := range ch {
fmt.Println(n, "を受信")
}
func Fn(ch1 chan<- int, ch2 <-chan string) {
var s string
select {
case ch1 <- 10:
fmt.Println("ch1送信")
case s = <- ch2:
fmt.Println("ch2受信")
// 受信も送信もできない場合
default:
fmt.Println("まだだよ")
}
}