版权声明:我已加入“维权骑士”(http://rightknights.com)的版权保护计划,知乎专栏“网路行者”下的所有文章均为我本人(知乎ID:弈心)原创,未经允许不得转载。

如果你喜欢我的文章,请关注我的知乎专栏“网路行者”https://zhuanlan.zhihu.com/c_126268929, 里面有更多像本文一样深度讲解计算机网络技术的优质文章。


Go中的变量和Python相比起来差异较大,并且Go拥有常量(constant)这个Python中完全不存在的数据类型和概念。还是那句话,《网络工程师的Golang之路》的读者对象是Netdevops领域的网络工程师,而几乎所有Netdevops的网工都是从Python学起并具备了相当程度的Python语法知识,因此本文以及本系列今后的文章中都会或多或少地出现Go和Python两门语言的对比,帮助Netdevops读者们触类旁通,更快更好地理解Go语言的基本语法。

本文会先总结Go和Python在变量上的主要差异,随后给出具体实验代码举例做演示,后半部分会重点讲解常量的概念。

变量重要概念

  • 在《网络工程师的Golang之路 -- 基础篇》中提到了Go是静态类型语言,声明变量时除了给变量取名外,还需指明变量的数据类型,变量的数据类型既可以显式声明也可以隐式声明。
  • 和Python不一样,在Go中声明变量后可以不用给变量赋值,如果声明变量后没有对变量赋值,Go会自动根据我们手动指定的数据类型来给该变量赋予与其类型相应的零值(Zero Values)。我们可以把零值理解为声明变量后系统为我们分配的缺省值,比如字符串的零值为空,整数和浮点数的零值为0(浮点数的零值也为0,而不是0.0),布尔值的零值为false等等。
  • 和Python一样,Go中的变量名由字母、数字、下划线组成,变量名可以以下划线开头,但是不能以数字开头,另外在Go中我们用//来为代码添加注释,这和用#做注释的Python不一样。
  • 和Python不一样,Go中的变量一旦被创建后,就必须使用,否则系统会返回"xx delcared but not used (xx为变量名)"的错误。
  • 和Python不一样,Go中声明变量和给变量赋值可以分开进行,即我们可以先声明一个变量但不给它赋值(此时该变量的值为系统根据它的数据类型自动赋予的零值),等下一步需要的时候再给该变量赋值。

创建变量

在Go中创建变量大致有三种格式和方法,分别讲解如下:

1. 标准格式:

var name [type]

标准格式中的var是用来声明变量的关键字,name是变量名,type则是我们要指定的变量的数据类型,注意type可以省去,使用type时为显式声明,不使用type时为隐式声明。

举例:

package main
 
import "fmt"
 
func main() {
    var a string = "网络工程师的Golang之路" //创建一个字符串变量a
    var b int = 100 //创建一个整数变量b
    var c bool = true //创建一个布尔变量c
    var d float32 //创建一个浮点数变量d,因为没有对其赋值,因此变量d此时的值为系统自动赋予给浮点数的零值:0
    var e = 200 //前面a,b,c,d都是显示地声明了它们的数据类型,这里也可以隐式声明变量e,系统会根据赋值自动判断e的数据类型。
    fmt.Println(a, b, c, d, e)
}

这里我们修改在《网络工程师的Golang之路 -- 基础篇》中创建的varaible.go文件来做演示:

注意这里d的数据类型虽然为float32,但是它的值为0(零值),不是0.0。

前面讲到了,在Go中声明变量和给变量赋值可以分开完成,比如这时如果想要把变量d的值从零值改为5.5,因为变量d已经被创建了,所以这时我们可以直接d = 5.5即可(给已经创建过的变量赋值无需再使用var关键字),举例如下:

package main
 
import "fmt"
 
func main() {
    var a string = "网络工程师的Golang之路"
    var b int = 100
    var c bool = true
    var d float32
    var e = 200
    d = 5.5
    fmt.Println(a, b, c, d, e)
}

声明变量后必须使用,否则系统会报错,举例如下:

package main
 
import "fmt"
 
func main() {
    var a string = "网络工程师的Golang之路"
    var b int = 100
    var c bool = true
    var d float32
    var e = 200
    d = 5.5
    fmt.Println(a, b, c)
}

这里我在使用fmt.Println()的时候只打印了变量a,b,c,故意漏掉了变量d和e,再尝试运行程序的时候可以看到系统返回了下面的报错,提示我们变量d和e虽然声明了但是没有被使用,变量被声明后必须使用的这点是Go和Python最大的区别之一,需要牢记。

另外Go语言中变量名可以包含字母、数字、下划线,变量名可以以下划线开头,但是不能以数字开头,否则系统会返回syntax error举例如下:

package main
 
import "fmt"
 
func main() {
    var a string = "网络工程师的Golang之路"
    var b int = 100
    var c bool = true
    var d float32
    var e = 200
    d = 5.5
    var a123_ string = "123_"
    var _123a int = 123
    var 123 int = 123
    fmt.Println(a, b, c, d, e, a123_, _123a, 123)
}

这里我们尝试创建变量123,但是执行程序的时候系统返回了syntax error: unexpected literal 123, expecting name这个异常。

2. 批量格式:

每次声明一个新变量都用到var这个关键词显然显得很繁琐,好在Go支持通过批量格式同时创建多个变量,方法是使用关键字var和括号(),然后在括号中间创建多个变量,举例如下:

package main

import "fmt"

func main() {
    var (
        a string = "网络工程师的Golang之路"
        b int    = 100
        c bool   = true
        d float32
        e = 200
    )
    fmt.Println(a,b,c,d,e)
}

3. 简短格式:

除标准格式和批量格式之外,Go语言还支持使用:=符号这种简短格式来声明变量(:=这个符号在Go中的官方术语叫做short assignment statement),简短格式不需要使用var关键字,也不需要手动指定变量的数据类型(隐式声明),你基本可以把它理解为我们在Python中创建变量的方式,区别仅仅在于Python中变量名和值是使用等号=连接的,而在Go中以简短格式声明变量名时变量名和值是用:=连接的,举例如下:

package main

import "fmt"

func main(){
    a := "网络工程师的Golang之路"
    b := 100
    c := true
    d := 5.5
    e := 200
    fmt.Println(a,b,c,d,e)
}

使用简短格式的时候需要注意,简短格式是用来声明新的变量的,不是用来改变已有的变量的值的,否则系统会返回“no new variables on left side of :=”的异常,举例如下:

这里我们已经用简短格式来创建了变量e(e:=200),如果继续尝试用简短格式来将变量e的值从200修改为300,则系统会报错,返回“no new variables on left side of :=”的异常。正确的做法是直接用e = 300即可以修改变量e的值。


常量

和Python不同,Go中存在着常量(constant)的概念,所谓常量是指在程序运行过程中,值会一直保持不变的量,比如说圆周率3.1415926、不支持扩展插槽的交换机的端口数量等等。在Go中常量的数据类型有限制,只能为字符串型、布尔型以及数字型(包括整数、浮点、复数),有关数据类型的知识将在下一节中讲到。

在Go中我们使用const这个关键字来声明常量,和变量一样,常量的数据类型既可以显式声明也可以隐式声明,举例如下:

package main
 
import "fmt"
 
func main() {
    const PI float64 = 3.14 //显示声明常量
    const number_of_sw_ports = 48 //隐式声明常量
    fmt.Println(PI)
    fmt.Println(number_of_sw_ports)
}

定类常量、未定类常量

在Go中常量又可以分为定类常量(Signed Constant)和未定类常量(Unsigned Constant)和,上面我们用显示声明,给出了数据类型的常量就叫做定类常量,而用隐式声明,没有给出数据类型的常量就叫做未定类常量。

Go是一门强数据类型的语言,在Go中,所有没有以变量定义的字符串,整数,浮点数,布尔值都归类为未定类常量。举个例子:

package main
 
import "fmt"
 
func main() {
    fmt.Println("Hello World!")
}

这里的“Hello World!”我们是直接用fmt.Println()打印出来的,没有将它赋值给任何变量。如果以Python的常规思维来讲,我们通常会认为这个“Hello World!”是字符串,但这个理解在Go中却是错误的,因为我们没有把"Hello World!"赋值给任何变量,此时"Hello World!"的数据类型为未定类字符串常量(unsigned string constant),它和我们通常理解的字符串变量是有本质区别的。

既然是未定类字符串常量,那么上面的程序也可以这么写:

package main
 
import "fmt"
 
func main() {
    const a = "Hello World!"
    fmt.Println(a)
}

这里我们以隐式声明的方式创建了未定类常量a,并将“Hello World!”赋值给了a,因此此时a的数据类型为未定类字符串常量。

再举一例:

package main
 
import "fmt"
 
func main() {
    n1 := 1
    n2 := 1.1
    n3 := n1 + n2
    fmt.Println(n3)
}

这里我们声明了3个变量:n1表示整数1, n2表示浮点数1.1,n3为n1和n2的和,在尝试打印出n3的值时Go报错“invalid operation: n1 + n2 (mismatched types int and float64)”,因为不同于Python,在Go中做数学运算时,数字的数据类型必须一样,我们不能直接把整数和浮点数拿来结合做任何形式的运算,整数只能和整数运算,浮点数只能和浮点数运算,这里我们需要用n3 = float64(n1) + n2,将n1转换为64位的浮点数后才能让程序正常运行,关于Go中整数和浮点数的数据类型会在后面章节中详细介绍,这里大家了解即可。

但是如果此时我们把代码修改如下会怎样呢?

package main
 
import "fmt"
 
func main() {
    fmt.Println(1 + 1.1)
}

可以看到,如果跳过声明n1和n2两个整数和浮点数的步骤,直接将1 + 1.1打印出来的话,是可以让Go程序正常运行得到正确结果的,为什么?还是因为未定类常量,此时1叫做未定类整数常量(unsigned integer constant),1.1叫做未定类浮点数常量(unsigned float constant),因为它俩本质上都属于未定类常量,所以可以直接1 + 1.1做运算。

理解了这点后,同理下面的Go程序也能正常运行:

package main
 
import "fmt"
 
func main() {
    const n1 = 1
    const n2 = 1.1
    n3 := n1 + n2
    fmt.Println(n3)
}

这里我们用隐式声明的方法创建了未定类常量n1和n2,因为此时n1和n2的数据类型相同,因此n3 := n1 + n2成立,程序运行无误。 请一路从Python学起的Netdevops读者们务必谨记Go中的未定类常量,它是Python中完全没有的概念,需要一些时间反复消化和适应。

未定类常量和定类常量相比有个优点就是它具备灵活性,举例如下:

package main
 
import "fmt"
 
func main() {
    const PI = 3.14
    var a float32 = PI
    var b float64 = PI
    fmt.Println(a)
    fmt.Println(b)
}

这里我们创建了一个未定类浮点数常量PI,因为未定类,所以我们可以将PI赋值给数据类型为float32的变量a以及数据类型为float64的变量b(Go中浮点数分为float32和float64,它们的区别会在后面讲到)。

如果创建定类浮点数常量PI(float64)的话,则我们只能将PI赋值给变量b(float64),无法将PI赋值给变量a(float32),系统会返回“cannot use PI (type float64) as type float32 in assignment”的异常:

其他常量知识点:

  • 和变量不同,声明常量后必须为其赋值,否则系统会返回“missing value in const declaration”的异常:
  • 和变量不同,创建常量后可以不使用:
  • 创建常量后不使用,VScode只会给出一个警告(warning),不影响程序的运行。但如果创建变量后不使用的话,那么VSCode会提示程序语法有错误,无法运行程序:
  • 常量一旦被声明后,则无法修改它的值:

下一篇连接: