【進行】基本语法全总结
简要概括
根据《A Tour of Go》的顺序,我个人总结了学习Go基础的内容。
包裹
包裹点数
-
- 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
}
功能
在Go中,函数被定义如下。
请参考以下代码
func <関数名>([引数]) [戻り値の型] {
[関数の本体]
}
函数(Function)的要点
-
- 引数の戻り値の型を書く必要がある。(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
}
变量
变量(Variable)积分
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
}
常数
常数点
-
- 定数は、constキーワードを使用して宣言する。
-
- 定数は、文字(character)、文字列(string)、boolean、数値(numeric)のみで使用可能。
- 定数は:=を使用して宣言することはできない。
参考代码
const Num = 2
func main(){
const Greetings = "Hello World"
fmt.Println(Greetings) // => Hello World
fmt.Println(Num) // => 2
}
对于循环
循环点
- 使用時に条件式等を囲む()は必要ありませんが処理を囲む{}は必要。
参考代码
func main(){
sum := 0
for i := 0; i < 5; i++ {
sum += i
}
fmt.Println(sum) //=> 10
}
如果(条件分岐)
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
}
切换(条件判断)
切换(条件分岐)点
-
- 選択されたcaseだけを実行してそれに続く全てのcaseやdefaultは実行されない。
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 的函数的执行延迟到调用该函数的函数结尾(执行 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)的要点
classに似た役割を提供する。(関連する変数をひとまとめにする。)
typeとstructを使用して定義する。(参考コード① ex1)
複数の初期化方法が存在する。(参考コード① ex2)
構造体内にメソッドmethodを定義できる。(参考コード② ex3)
継承に似た機能として構造体の埋め込みが可能(参考コード③ ex4)
参考代码1
// 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
}
Refer to Code #3. (请参考第三段代码)
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
}
数组。
数组的重点
-
- 配列とは、同じ型を持つ値(要素)を並べたもの。(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]
}
切片
切片点
-
- 配列とは異なり長さ指定の必要なし。(参考コード① 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!を表示する。
}
}
地圖 liè)
地图(连想数组)点
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[]
}
参考代码2
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)
范围点
-
- スライスやマップに使用すると反復毎に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)点
-
- 任意の型が__「どのようなメソッドを実装するべきか」__を規定するためのもの。
-
- インターフェースの定義の内容は、単なるメソッドリストである。
- オブジェクト指向言語でいうところのポリモーフィズムと同様の機能を実現可能。
在参考代码1中,有两个结构体Person和Person2,每个结构体中都定义了intro()方法。每个结构体都有名为IntroForPerson()和IntroForPerson2()的方法,用于执行各自的intro()方法。
参考代码①
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
}
目前存在着IntroForPerson和IntroForPerson2具有相同行为的方法,这样会造成冗余。因此,可以像__参考代码2__那样将重复的方法提取到接口中。
参考代码2
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)点
-
- 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")
}
频道
渠道(チャネル)积分
-
- 組み込み関数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の値を受け取るまでの完了待ち。送られてきた値は破棄
}