Go语言由于其高性能、高并发、语法简单易学习、标准库丰富、工具链完善、编译迅速、静态链接、跨平台、垃圾回收等特点被广泛使用,像字节跳动、腾讯、微博、百度、美团、谷歌等公司都在使用Go语言,下面就来介绍Go语言基础语法和常用特性。
一、基础语法
1.Hello World
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
package main代表这个文件属于一个main包的一部分,main包也就是程序的入口包,那么这个文件就是程序的入口文件,第三行开始导入了标准库里的“fmt”包,这个包主要是用来往屏幕输入、输出字符串和格式化字符串,第七行开始是main的函数,在main函数里调用了fmt.Println()来输出Hello World。
2.变量
Go语言是一门强类型的语言,每一个变量都有它的变量类型,常见的变量类型有:字符串、整数、浮点型、布尔型。
变量的声明有两种方式:
①var name = value;
②name := value;
var a = 1
f := float32(e)
常量的声明用①这种方式,同时把var替换成const即可。
const h = 500
注:Go语言中的常量没有确定的类型,它会根据使用的上下代码自动确定类型。
3.if else
var grade = 98
func main() {
if grade >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
}
Go语言中的if else和C、C++中的if else很类似,不同点在于:
①Go语言中if后面不需要括号,即使在写代码时写了括号,在保存的时候编辑器会自动去掉这个括号。
②Go语言中if后面必须直接接大括号,不能把if语句里面的代码写在同一行。
4.循环
for i := 0; i < 3; i++ {
if i%2 == 0 {
break
}
fmt.Println(i)
}
Go语言中的循环没有while和do while循环,只有for循环。上面代码中的第一个for循环是死循环,for后面三段中的任意一段代码都可以省略。
注:continue继续循环,break跳出循环。
5.switch
i := two
switch i {
case one:
fmt.Println("1")
case two:
fmt.Println("2")
default:
fmt.Println("other")
}
Go语言中的switch分支结构也与C和C++类似,同样的在switch后面的变量名不需要加括号,在C和C++里,如果在case分支后不加break,那么会从满足要求的分支那一直运行下去,直到运行完所有的分支,而在Go语言里是不需要加break来及时终止的。并且Go语言中的switch更加强大,它可以使用任意的变量类型甚至可以用来代替任意的if else语句。
6.数组
数组是一个具有编号,且长度固定的元素序列,它是一个存储相同类型元素的集合。
num := [5]int{3, 1, 2, 4, 5}
fmt.Println(a)
7.切片
切片是可变长度的数组,可以任意时刻去更改长度。我们可以用make()来创建切片,切片可以用append()追加元素。可以用copy()拷贝数据。
注:在使用append时,要将返回值赋值回原数组。
animals := make([]string, 3)
animals[0] = "monkey"
animals[1] = "bear"
animals[2] = "bird"
animals = append(animals, "fish")
c := make([]string, 4)
copy(c, animals)
8.map
在其他编程语言里,map可能被称作哈希或者被称作字典,map是实际使用过程中使用最频繁的数据结构。我们可以用make()来创建map。
grades := make(map[string]int)
grades["Tom"] = 88
grades["Jane"] = 92
fmt.Println(grades["Tom"])
delete(grades,"Jane")
9.range
对于一个数组、切片或者是map,我们可以使用range快速遍历,range能使代码变得更加简洁。range遍历数组的时候会返回两个值,第一个值为索引,第二个值为对应位置的值,如果不需要索引可以使用下划线去忽略。
nums := []int{1, 2, 3}
sum := 0
for i, num := range nums {
fmt.Println("index:", i, "num:", num)
}
10.函数
Go语言和其他很多语言不一样的是它的变量类型是后置的。Go语言的函数原生支持返回多个值,在实际的业务逻辑代码里面几乎所有函数都会返回两个值,第一个值是真正的返回结果,第二个值是错误信息。
func add(a int, b int) int {
return a + b
}
func main() {
res := add(21, 29)
fmt.Println(res)
}
11.指针
Go语言中也支持指针,但与C和C++里的指针相比,Go语言指针的操作非常有限,主要用途就是对传入参数进行修改。
func add3(n *int) {
*n += 3
}
func main() {
n := 7
add3(&n)
fmt.Println(n) // 输出结果为10
}
12.结构体与结构体方法
结构体是带类型的字段集合,在初始化的时候,我们需要传入每个字段的初始值。
结构体方法非常类似其它语言里的类成员函数。
type user struct {
name string
sex string
}
func (a *user) changeSex(newSex string) {
a.sex = newSex
}
func main() {
a := user{name: "Tom", sex: "man"}
fmt.Println(a.name)
var b user
b.name = "Tony"
b.sex = "woman"
b.changeSex(man)
fmt.Println(b)
二、常用特性
1.错误处理
Go语言使用一个单独的返回值来传递错误信息,不同于Java里面使用的异常,Go语言的处理方式能够很清楚的知道是哪个函数返回了错误,并且能够用简单的if else去处理错误。在函数的返回值类型的后面加上一个error,就代表这个函数可能会返回错误。在函数实现的时候,就需要同时return两个值,如果出现错误的话,那么就可以return一个nil和一个error。如果没有出现错误的话,那么就返回原本的结果和一个nil。
2.字符串操作、字符串格式化
在Go语言标准库string包里面有很多字符串工具函数,比如:Contains()、Count()、Index()、Join()、Repeat()。
func main() {
a := "hello"
fmt.Println(strings.Contains(a, "ll")) // true
fmt.Println(strings.Count(a, "l")) // 2
fmt.Println(strings.Index(a, "ll")) // 2
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
fmt.Println(strings.Repeat(a, 2)) // hellohello
fmt.Println(len(a)) // 5
}
在标准库的fmt包里面有很多字符串格式化相关的方法,最常用的就是fmt.Println()(打印多个变量并换行),也可以通过fmt.printf()支持的各种打印格式来输出字符串,其中%v可以用来打印任意类型的变量,也可以用%+v打印详细结果,而%#v更加详细。
name := "Tom"
sex := man
fmt.Printf("姓名:%v,性别:%v\n", name, sex)
3.JSON处理
Go语言的JSON操作非常简单,对于一个已有的结构体,只要保证每个字段的第一个字母是大写,也就是Go语言中的公开字段,那么这个结构体就能用json.marshal()去序列化,序列化之后会变成一个字符串。序列化之后的字符串可以用json.unmarshal()去反序列化到一个空的变量里面。一般情况下序列化出来的字符串的风格是大写字母开头,我们可以在结构体定义变量时,在后面用json的tag等去修改输出时的字段名。
4.时间处理
在 Go 语言里面最常用的就是time.now(),它可以快速获取当前时间,我们可以用time.date()去构造一个带时区的时间,还可以用t.Sub()让两个时间相减得到一个时间段,还可以用t.Format()去格式化一个时间到一个时间字符串,还可以用t.Unix()获取一个时间戳。
5.数字解析
Go 语言中关于字符串和数字之间的转换都在strconv这个包下。我们可以用ParseInt()或者ParseFloat()来解析一个字符串,在ParseInt()里有三个参数,第一个参数是字符串,第二个参数代表进制,如果此位置为0,代表自动推测,第三个参数代表返回值的精度。我们也可以用Atoi()快速把十进制字符串转换成数字,用itoA()把数字转成字符串。
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f)
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n)
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n)
n2, _ := strconv.Atoi("123")
fmt.Println(n2)
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err)
}
6.进程信息
我们可以用os.Args来获取进程在执行的时候命令行参数,可以用os.Getenv()和os.Setenv()分别来获取和写入环境变量,可以用exec.Command()来快速启动子进程并且获取其输入输出。
fmt.Println(os.Args)
fmt.Println(os.Getenv("PATH"))
fmt.Println(os.Setenv("AA", "BB"))
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Println(string(buf))
}