GO 语言基础速查
来源
https://www.runoob.com/go/go-tutorial.html
Go 语言结构
Go 语言的基础组成有以下几个部分:
- 包申明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
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)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
数据类型
-
布尔型
布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
-
数字类型
整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
-
字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
-
派生类型: 包括:
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_name1,v_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
-
和 C 语言的 for 一样:
for init; condition; post { } -
和 C 的 while 一样:
for condition { } -
和 C 的 for(;;) 一样:
for { } -
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)
}
}