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 = 123
注: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 := 1; i < 5; i++ {
if i%2 == 0 {
break
}
fmt.Println(i)
}
Go 语言中仅存在 for 循环,并没有 while 和 do while 循环。上述代码中的第一个 for 循环示例是常见的循环形式,不过需要注意的是,for 后面三段代码中的任意一段都可以根据实际需求省略。
注:continue 语句用于让循环继续执行下一次迭代,break 语句则用于跳出当前循环。
5.switch
i := three
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 := [6]int{3, 1, 2, 4, 5, 6}
fmt.Println(a)
7.切片
切片是一种长度可变的数组结构,能够在任意时刻对其长度进行更改。我们可以借助 make () 函数来创建切片,通过 append () 函数可以向切片追加元素,利用 copy () 函数则能够实现数据的拷贝操作。
注:在使用 append () 函数时,需要将其返回值重新赋值给原数组。
animals := make([]string, 3)
animals[0] = "cat"
animals[1] = "bird"
animals[2] = "dog"
animals = append(animals, "pig")
c := make([]string, 4)
copy(c, animals)
8.map
在其他一些编程语言中,map 可能会被称作哈希或者字典,在实际的编程应用过程中,map 是使用频率非常高的数据结构。我们可以利用 make () 函数来创建 map。
grades := make(map[string]int)
grades["Tom"] = 66
grades["Jane"] = 74
fmt.Println(grades["Tom"])
delete(grades,"Jane")
9.range
对于数组、切片或者 map 等数据结构,我们可以使用 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 类型,就意味着这个函数有可能会返回错误。在函数具体实现时,就需要同时返回两个值,如果出现错误情况,那么就返回一个 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))
}
总之,Go 语言具有丰富的语法特性和实用的常用功能,这些特点使其在众多企业的开发中得到广泛应用。