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

79 阅读4分钟

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 intvar (
    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还有许多特性,我们以后再进行详细介绍。