GO 语言基础速查

5 minute read

来源

https://www.runoob.com/go/go-tutorial.html

Go 语言结构

Go 语言的基础组成有以下几个部分:

  1. 包申明
  2. 引入包
  3. 函数
  4. 变量
  5. 语句 & 表达式
  6. 注释
package main // 包声明
/*
   包声明:
   
   必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main 表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

   注意:文件名与包名没有直接关系,不一定要将文件名与包名定成同一个。文件夹名与包名没有直接关系,并非需要一致。同一个文件夹下的文件只能有一个包名,否则编译报错。
*/
import "fmt" // 引入包
/*
   引入包:
   
   告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
*/

func main() { // 函数
   /* 这是我的第一个简单的程序 */
   fmt.Println("Hello, World!")  // 语句
/*
   语句:

   当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。
*/
}

Go 语言语法

行分隔符

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。

如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。

标识符

标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母 (A~Z 和 a~z) 数字 (0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。

数据类型

  1. 布尔型

    布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。

  2. 数字类型

    整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。

  3. 字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。

  4. 派生类型: 包括:

    I. 指针类型(Pointer)

    II. 数组类型

    III. 结构化类型 (struct)

    IV. Channel 类型

    V. 函数类型

    VI. 切片类型

    VII. 接口类型(interface)

    VIII. Map 类型

变量

Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。

申明变量及类型

声明变量的一般形式是使用 var 关键字,基本格式如下。

var identifier type

可以一次声明多个变量:

var identifier1, identifier2 type

指定变量类型,如果没有初始化,则变量默认为零值。零值不一定是数值为 0,数值类型(包括 complex64/128)为 0,布尔类型为 false,字符串为 ““(空字符串),指针等类型为 nil。

显示申明变量,推断类型

有点类似于 C++ 中的 auto,格式如下。

var v_name = value

隐式申明变量,推断类型

格式如下。

v_name := value

可以串联使用。

v_name1v_name2 := value1,value2

交换两个变量的值

var a,b int = 3,4
a,b = b,a

常量

const identifier [type] = value

条件语句

if..else

if 布尔表达式 {

} else {

}

switch

switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough 。也可以主动使用 break 使 case 提前终止。

var1 可以是变量,也可以类型。

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}
switch x.(type){
    case type:
       statement(s);      
    case type:
       statement(s); 
    /* 你可以定义任意个数的 case */
    default: /* 可选 */
       statement(s);
}

select

用于通信。

循环

for

  1. 和 C 语言的 for 一样:

    for init; condition; post { }
    
  2. 和 C 的 while 一样:

    for condition { }
    
  3. 和 C 的 for(;;) 一样:

    for { }
    
  4. For-each range

    val3 需要是一个可迭代类型。

    for val1,val2:= range val3 {
                statements
         } 
    

循环控制块

continue,break,goto 和 C 语言用法一致。

函数

函数定义

func function_name( [parameter list] ) [return_types] {
   函数体
}

函数调用

函数一定定义之后,就可以再任意位置使用,因此可能会出现“先使用后定义”的情况。

数组

一维数组

var variable_name [SIZE] variable_type

多维数组

var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type

指针

指针类型用原数据类型前加 * 表示。

nil 表示空指针。

GO 语言结构体

结构体的定义

结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:

type struct_variable_type struct {
   member definition
   ...
   member definition
}

结构体的操作

C++ 中的结构体也可以有操作,我觉得和类很像。

结构的操作函数与普通函数定义的区别在于 func 之后多加 (变量名 结构类型)。

type Goods struct {
    Name  string
    Price int
}

func (g Goods) GetName() string {
    return g.Name
}

func (g Goods) SetName(name string) {
    g.Name = name
}

func (g Goods) String() {
    fmt.Println("I am Goods")
}

GO 语言接口

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。

/* 定义接口 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* 定义结构体 */
type struct_name struct {
   /* variables */
}

/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
   /* 方法实现*/
}

错误处理

Go 语言通过内置的错误接口提供了非常简单的错误处理机制。

error 类型是一个接口类型,这是它的定义:

type error interface {
    Error() string
}

并发

goroutine

go 函数名( 参数列表 ) 创建一个新的 goroutine,类似于一个新线程。

package main

import (
        "fmt"
        "time"
)

func say(s string) {
        for i := 0; i < 5; i++ {
                time.Sleep(100 * time.Millisecond)
                fmt.Println(s)
        }
}

func main() {
        go say("world")
        say("hello")
}

通道(channel)

通道(channel)是用来传递数据的一个数据结构。

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据并把值赋给 v
package main

import "fmt"

func sum(s []int, c chan int) {
        sum := 0
        for _, v := range s {
                sum += v
        }
        c <- sum // 把 sum 发送到通道 c
}

func main() {
        s := []int{7, 2, 8, -9, 4, 0}

        c := make(chan int)
        go sum(s[:len(s)/2], c)
        go sum(s[len(s)/2:], c)
        x, y := <-c, <-c // 从通道 c 中接收

        fmt.Println(x, y, x+y)
}

完整代码

package main

import (
	"fmt"
	"time"
)

var x, y int = 1, 2
var ( // 这种因式分解关键字的写法一般用于声明全局变量,不可赋初值
	z1 int
	z2 bool
)

func main() {

	fmt.Println("Hello world.")

	var a1 string = "Runoob"
	fmt.Println(a1)

	var b, c int = 1, 2
	fmt.Println(b, c)
	b, c = c, b
	fmt.Println(b, c)

	var i int
	var f float64
	var r bool
	var s string
	fmt.Printf("%v %v %v %q\n", i, f, r, s)

	var t = true
	fmt.Println(t)

	p, q := 22, 33
	fmt.Println(p, q)

	/* 局部变量定义 */
	var a int = 100

	/* 判断布尔表达式 */
	if a < 20 {
		/* 如果条件为 true 则执行以下语句 */
		fmt.Printf("a 小于 20\n")
	} else {
		/* 如果条件为 false 则执行以下语句 */
		fmt.Printf("a 不小于 20\n")
	}
	fmt.Printf("a 的值为 : %d\n", a)

	/* 定义局部变量 */
	var grade string = "B"
	var marks int = 90

	switch marks {
	case 90:
		grade = "A"
	case 80:
		grade = "B"
	case 50, 60, 70:
		grade = "C"
	default:
		grade = "D"
	}

	switch {
	case grade == "A":
		fmt.Printf("优秀!\n")
	case grade == "B", grade == "C":
		fmt.Printf("良好\n")
	case grade == "D":
		fmt.Printf("及格\n")
	case grade == "F":
		fmt.Printf("不及格\n")
	default:
		fmt.Printf("差\n")
	}
	fmt.Printf("你的等级是 %s\n", grade)

	numbers := [6]int{1, 2, 3, 5}
	for i, x := range numbers {
		fmt.Printf("第 %d 位 x 的值 = %d\n", i, x)
	}

	type Books struct {
		title   string
		author  string
		subject string
		bookID  int
	}

	book := Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407}
	fmt.Println(book)

	fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
	fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", bookID: 6495407})
	fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})

	var Book1 Books /* 声明 Book1 为 Books 类型 */

	/* book 1 描述 */
	Book1.title = "Go 语言"
	Book1.author = "www.runoob.com"
	Book1.subject = "Go 语言教程"
	Book1.bookID = 6495407

	/* 打印 Book1 信息 */
	fmt.Printf("Book 1 title : %s\n", Book1.title)
	fmt.Printf("Book 1 author : %s\n", Book1.author)
	fmt.Printf("Book 1 subject : %s\n", Book1.subject)
	fmt.Printf("Book 1 bookID : %d\n", Book1.bookID)

	var goods Goods
	goods.SetName("12")
	fmt.Println(goods.GetName())
	goods.String()

	/* 声明变量,默认 map 是 nil */
	var countryCapitalMap map[string]string
	countryCapitalMap = make(map[string]string)

	/* map插入key - value对,各个国家对应的首都 */
	countryCapitalMap["France"] = "巴黎"
	countryCapitalMap["Italy"] = "罗马"
	countryCapitalMap["Japan"] = "东京"
	countryCapitalMap["India "] = "新德里"
	/*使用键输出地图值 */
	for country := range countryCapitalMap {
		fmt.Println(country, "首都是", countryCapitalMap[country])
	}
	delete(countryCapitalMap, "France")
	for country := range countryCapitalMap {
		fmt.Println(country, "首都是", countryCapitalMap[country])
	}

	var phone Phone

	phone = new(NokiaPhone)
	phone.call()

	phone = new(IPhone)
	phone.call()

	go say("world")
	say("hello")

}

// Goods : 这个类用于测试结构的操作
type Goods struct {
	Name  string
	Price int
}

// GetName : 得到 Name 属性
func (g *Goods) GetName() string {
	return g.Name
}

// SetName : 重置 Name 属性
func (g *Goods) SetName(name string) {
	g.Name = name
}

// String : 打印
func (g *Goods) String() {
	fmt.Println("I am Goods")
}

// Phone : 定义了一个接口,关键词为 interface
type Phone interface {
	call()
}

// NokiaPhone : 定义了一个结构体
type NokiaPhone struct {
}

// call : NokiaPhone 的 call 操作
func (nokiaPhone NokiaPhone) call() {
	fmt.Println("I am Nokia, I can call you!")
}

// IPhone : 定义了一个结构体
type IPhone struct {
}

// call : IPhone 的 call 操作
func (iPhone IPhone) call() {
	fmt.Println("I am iPhone, I can call you!")
}

func say(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}