Go的特性
Go可以直接将代码编译成机器码,而不依赖其他的环境。可以直接运行,不像Java、C++,还需要安装一些其他的库。
Go是一门静态语言,在编译的时候就可以检查出来隐藏的大多数问题。
Go天生支持并发,能够充分利用多核。
package main
import "fmt"
func goFunc(i int) {
fmt.Println(i)
}
func main() {
for i := 0; i < 10000; i++ {
go goFunc(i) // 开启一个并发携程
}
}
Go有强大的标准库,例如runtime系统调度机制、高效的GC垃圾回收、丰富的标准库(加解密,email,进程、线程、文本、数据结构算法、压缩、网络等等)。
Go只有25个关键字,可以内嵌C语法支持,面向对象特征(继承、多态、封装),跨平台。
语法
Hello World
学习一门语言,先来一个Hello World。
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
第一行代码package main定义了包名。必须在源代码的第一行指明这个文件属于哪个包,例如package main。每个Go应用程序必须包含一个名为main的包。
下一行的import fmt告诉Go编译器,这个程序需要使用fmt包的函数,或者其他元素,fmt包实现了格式化输入输出的函数。
下一行的func main()是程序的入口函数,每个程序必须包含且只能有一个。
注意:定义函数的时候{ 必须和函数名在同一行,不能像C++一样另起一行。
Go也不需要行末添加分号。
变量
Go声明变量的方式太多太多种了。通常使用var关键字。格式是:var v_name v_type。
指明变量类型
package main
import "fmt"
func main() {
var i int
fmt.Println(i) // 0
}
声明不赋值会给一个默认值,整数是默认值是0。
根据值自动判断变量类型
var v_name = value
还可以省略var,
v_name := value
注意 ::=左边的变量名不应该是已经声明过的。否则会导致编译错误。而且这种方式只能在函数体中使用
例如:
var a int = 10
var b = 20
c := 30
多变量声明
package main
var a, b int
var (
c int
d bool
)
var e, f int = 1, 2
var g, h = 123, "demo"
func main() {
_, x := 2, 10
}
var ()这种方式通常用于声明全局变量。
_, x := 2, 10,2的赋值会被丢弃掉,变量_不具备读特性。
常量
常量是一个简单值的标识符,在程序运行时,不能被改变。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
常量的定义格式:const identifier [type] = value。
[type]类型说明符可以被省略,编译器可以根据变量的值来推断其类型。
显示类型定义const a string "string"。
隐式类型定义const PI = 3.1415926。
函数
Go 函数可以返回多个值,例如:
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("A", "B")
fmt.Println(a, b)
}
defer
defer语句被用于预定对一个函数的调用。可以把这类被defer语句调用的函数称为延迟函数。
defer作用:
- 释放占用的资源
- 捕捉处理异常
- 输出日志
如果一个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行。
func fun(){
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
defer fmt.Println("4")
}
func main() {
fun()
}
-----
out:
4
3
2
1
recover错误拦截
运行时panic异常一旦被引发就会导致程序崩溃。
Go语言提供了专用于“拦截”运行时panic的内建函数recover。
注意: recover只有在defer调用的函数中有效。如果程序没有异常,不会打印错误信息。
slice
Go 语言切片是对数组的抽象。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片动态数组,与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
map
map和slice类似,只不过是数据结构不同,下面是map的一些声明方式。
package main
import (
"fmt"
)
func main() {
//第一种声明
var test1 map[string]string
//在使用map前,需要先make,make的作用就是给map分配数据空间
test1 = make(map[string]string, 10)
test1["one"] = "php"
test1["two"] = "golang"
test1["three"] = "java"
fmt.Println(test1) //map[two:golang three:java one:php]
//第二种声明
test2 := make(map[string]string)
test2["one"] = "php"
test2["two"] = "golang"
test2["three"] = "java"
fmt.Println(test2) //map[one:php two:golang three:java]
//第三种声明
test3 := map[string]string{
"one" : "php",
"two" : "golang",
"three" : "java",
}
fmt.Println(test3) //map[one:php two:golang three:java]
language := make(map[string]map[string]string)
language["php"] = make(map[string]string, 2)
language["php"]["id"] = "1"
language["php"]["desc"] = "php是世界上最美的语言"
language["golang"] = make(map[string]string, 2)
language["golang"]["id"] = "2"
language["golang"]["desc"] = "golang抗并发非常good"
fmt.Println(language) //map[php:map[id:1 desc:php是世界上最美的语言] golang:map[id:2 desc:golang抗并发非常good]]
//增删改查
// val, key := language["php"] //查找是否有php这个子元素
// if key {
// fmt.Printf("%v", val)
// } else {
// fmt.Printf("no");
// }
//language["php"]["id"] = "3" //修改了php子元素的id值
//language["php"]["nickname"] = "啪啪啪" //增加php元素里的nickname值
//delete(language, "php") //删除了php子元素
fmt.Println(language)
}
Go还有许多特性,我们以后再进行详细介绍。