Go 语言入门指南:基础语法和常用特性解析 | 青训营

43 阅读7分钟

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))
}