Go语言中的语法点/注意事项/冷知识 | 青训营笔记

343 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

本文会整理Go语言中的语法点/注意事项/冷知识等等内容,并尽量给出证明以及示例代码。

变量声明与导包

1、如果代码中存在未使用的变量或者导入的包,则无法通过编译。不过全局变量可以只声明而不使用

 package main
 ​
 // "sort" imported but not used
 import "sort" 
 ​
 // 无报错
 var all int
 ​
 func main() {
     // local declared but not used
     var local int
 }

2、导入同一个 module 下的其他包时,会以模块名(即 go.mod 里的module [name] 这个 name)作为根目录

go.mod内容

 module note
 ​
 go 1.18

导入的pkg包的代码

 package pkg
 ​
 import "fmt"
 ​
 func init() {
     fmt.Println("init")
 }
 ​
 func Fun() {
     fmt.Println("pkg Fun!")
 }

导入该项目目录下的pkg包(文件夹)

 import "note/pkg" // 只会执行包里的 init() 函数
 ​
 func main() {
     pkg.Fun()
 }

3、特殊导包的模式有三种

  1. 起别名
  2. 只进行初始化
  3. 不写包名即可调用,类似静态导包
 package main
 ​
 import (
     f "fmt"      // 起另一个名字,但是这样原来的包名会不可用
     _ "note/pkg" // 只会执行包里的 init() 函数
     . "math"     // 调用包里的函数等时可以不写包名
 )
 ​
 func main() {
     f.Println("Another fmt")
     //fmt.Println("fmt") // undeclared name: fmt
     f.Printf("Max(1.2, 1.3): %v\n", Max(1.2, 1.3)) // 调用Max()无需写包名
 }

执行结果

 init
 Another fmt
 Max(1.2, 1.3): 1.3

4、可以使用简短声明来给已声明的变量赋值,但这需要 := 的左边必须有一个新声明的变量

 package main
 ​
 import "fmt"
 ​
 func main() {
     a := 0
     fmt.Println(&a, ":", a)
     a, b := 1, 2
     // a, _ := 1, 2 // no new variables on left side of :=
     fmt.Println(&a, ":", a)
     fmt.Println(b)
 }

结果:

 0xc000012098 : 0
 0xc000012098 : 1
 2

这说明两个 a 的地址相同,是同一个变量

这个特性用的最多的地方当然是 Go 比较著名的异常处理 if err != nil 的前一句(即接收函数返回值时)

 func main() {
     i1, err := divide(6, 3)
     if err != nil {
         fmt.Println(err.Error())
     }
     fmt.Println("result1:", i1)
     fmt.Println(&err) // 0xc000054250
 ​
     i2, err := divide(1, 0)
     if err != nil {
         fmt.Println(err.Error())
     }
     fmt.Println("result1:", i2)
     fmt.Println(&err) // 0xc000054250
 }
 ​
 func divide(divisor, dividend int) (int, error) {
     if dividend == 0 {
         return 0, errors.New("被除数不能为零")
     }
     return divisor / dividend, nil
 }

结果两个 err 的地址也是相同的

5、Go中的字符类型 rune 基本等价于 int32

类型定义

 type rune = int32
 rune is an alias for int32 and is equivalent to int32 in all ways. It is used, by convention, to distinguish character values from integer values.

输出字符变量的变量类型

 func main() {
     c := 'a'
     fmt.Printf("%T", c) //int32
 }

字符串相关

1、Go 的内置函数 len() 返回的是字符串的 byte 数量,如果要获取中文字符串的中文字数,可以转换成 []rune 再用 len() 获取

 func main() {
     s := "对的。"
     fmt.Println(len(s))         //9
     fmt.Println(len([]byte(s))) //9
     fmt.Println(len([]rune(s))) //3 
 }

结果解释:在UTF-8编码中,一个中文字符等于三个字节,一个中文标点符号占三个字节。

2、string 类型的变量值不能为 nil

和Java以及C++不同,Go中的string是基本数据类型,string 的空值是 ""。

 var s string = nil //cannot use nil as string value in variable declaration

冷知识

1、go 语言里的关键字可以做为变量名,但是并不推荐

 func main() {
     true := false
     fmt.Println(true) //false
 }