【進行】基本语法全总结

简要概括

根据《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の値を受け取るまでの完了待ち。送られてきた値は破棄
}
广告
将在 10 秒后关闭
bannerAds