变量是掌握的重要编程概念。 它们是代表您在程序中使用的值的符号。
本教程将介绍在您创建的Go程序中使用它们的一些变量基础知识和最佳实践。
在技术术语中,变量将存储位置分配给与符号名称或标识符相关联的值。 我们使用变量名称来引用计算机程序中的存储值。
我们可以将变量视为一个带有名称的标签,并将其绑定到一个值上。
假设我们有一个整数1032049348
,我们希望将它存储在一个变量中,而不是一遍又一遍地连续重新输入长数。 为实现这一目标,我们可以使用易于记忆的名称,例如变量i
。 要在变量中存储值,我们使用以下语法:
i := 1032049348
我们可以将此变量视为与值绑定的标签。
标签上写有变量名称i
,并且与整数值1032049348
。
短语i := 1032049348
是一个声明和赋值语句,由几个部分组成:
i
) :=
) 1032049348
) int
)推断出的数据类型 稍后我们将看到如何在下一节中明确设置类型。
这些部分一起构成了将变量i
设置为等于整数1032049348
的值的1032049348
。
一旦我们将变量设置为等于值,我们就会初始化或创建该变量。 完成后,我们就可以使用变量而不是值。
一旦我们将i
设置为等于1032049348
的值,我们就可以使用i
代替整数,所以让我们打印出来:
package main
import "fmt"
func main() {
i := 1032049348
fmt.Println(i)
}
1032049348
我们还可以通过使用变量快速轻松地进行数学运算。 使用i := 1032049348
,我们可以使用以下语法减去整数值813
:
fmt.Println(i - 813)
1032048535
在这个例子中,Go为我们做数学运算,从变量i
减去813以返回总和1032048535
。
说到数学,变量可以设置为等于数学方程的结果。 您还可以将两个数字相加并将总和的值存储到变量x
:
x := 76 + 145
您可能已经注意到此示例与代数类似。 与我们使用字母和其他符号来表示公式和公式中的数字和数量的方式相同,变量是表示数据类型值的符号名称。 要获得正确的Go语法,您需要确保您的变量位于任何方程的左侧。
让我们继续打印x
:
package main
import "fmt"
func main() {
x := 76 + 145
fmt.Println(x)
}
221
Go返回值221
因为变量x
被设置为等于76
和145
的总和。
变量可以表示任何数据类型,而不仅仅是整数:
s := "Hello, World!"
f := 45.06
b := 5 > 9 // A Boolean value will return either true or false
array := [4]string{"item_1", "item_2", "item_3", "item_4"}
slice := []string{"one", "two", "three"}
m := map[string]string{"letter": "g", "number": "seven", "symbol": "&"}
如果您打印任何这些变量,Go将返回该变量等效的内容。 让我们使用字符串slice
数据类型的赋值语句:
package main
import "fmt"
func main() {
slice := []string{"one", "two", "three"}
fmt.Println(slice)
}
[one two three]
我们将[]string{"one", "two", "three"}
的slice值赋给变量slice
,然后使用fmt.Println
函数通过调用slice
打印出该值。
变量的工作原理是在计算机中划出一小块内存,接受与该空间关联的指定值。
在Go中,有几种方法可以声明变量,在某些情况下,有多种方法可以声明完全相同的变量和值。
我们可以在没有初始化的情况下声明一个名为i
of data type int
的变量。 这意味着我们将声明一个空格来放置一个值,但不给它一个初始值:
var i int
这将创建一个声明为数据类型为int
的变量。
我们可以使用equal( =
)运算符初始化值,如下例所示:
var i int = 1
在Go中,这两种形式的声明都称为长变量声明 。
我们也可以使用短变量声明 :
i := 1
在这种情况下,我们有一个名为i
的变量,以及一个int
的数据类型。 当我们不指定数据类型时,Go将推断数据类型。
通过三种声明变量的方式,Go社区采用了以下习语:
当你没有初始化变量时,只使用long form, var i int
。
在声明和初始化时使用简短形式, i := 1
。
如果您不希望Go推断您的数据类型,但您仍希望使用短变量声明,则可以使用以下语法将值包装在所需类型中:
i := int64(1)
在我们初始化值时,Go在使用长变量声明表单时不被认为是惯用的:
var i int = 1
遵循Go社区通常如何声明变量以便其他人可以无缝读取您的程序是一种很好的做法。
所有内置类型都具有零值。 即使从未分配了值,任何已分配的变量都可以使用。 我们可以看到以下类型的零值:
package main
import "fmt"
func main() {
var a int
var b string
var c float64
var d bool
fmt.Printf("var a %T = %+v\n", a, a)
fmt.Printf("var b %T = %q\n", b, b)
fmt.Printf("var c %T = %+v\n", c, c)
fmt.Printf("var d %T = %+v\n\n", d, d)
}
var a int = 0
var b string = ""
var c float64 = 0
var d bool = false
我们在fmt.Printf
语句中使用了%T
谓词。 这告诉函数打印变量的data type
。
在Go中,因为所有值都具有zero
值,所以我们不能像其他语言一样具有undefined
值。 例如,某些语言中的boolean
可能是undefined
, true
或false
,这允许变量有three
状态。 在Go中,布尔值不能超过two
状态。
变量的命名非常灵活,但要记住一些规则:
_
)组成。 遵循这些规则,让我们看看有效和无效的变量名称:
有效 | 无效 | 为什么无效 |
---|---|---|
userName | user-name | 连字符是不允许的 |
name4 | 4name | 不能以数字开头 |
user | $user | 不能使用符号 |
userName | user name | 不能超过一个字 |
此外,在命名变量时,请记住它们区分大小写。 这些名称userName
, USERNAME
, UserName
和uSERnAME
都是完全不同的变量。 最好避免在程序中使用类似的变量名称,以确保您和您的协作者(当前和未来)能够保持变量的正确性。
虽然变量区分大小写,但变量的第一个字母的大小写在Go中具有特殊含义。 如果变量以大写字母开头,则该变量可在其声明(或exported
)的包外部访问。 如果变量以小写字母开头,则它仅在声明它的包中可用。
var Email string
var password string
Email
以大写字母开头,可以通过其他包访问。 password
以小写字母开头,只能在声明的包中访问。
在Go中使用非常简洁(或简短)的变量名称是很常见的。 考虑到在变量中使用userName
和user
之间的选择,选择user
将是惯用的。
范围也在变量名称的简洁性中起作用。 规则是变量存在的范围越小,变量名称越小:
names := []string{"Mary", "John", "Bob", "Anna"}
for i, n := range names {
fmt.Printf("index: %d = %q\n", i, n)
}
我们在更大的范围内使用变量names
,因此通常会给它一个更有意义的名称来帮助记住它在程序中的含义。 但是,我们在下一行代码中立即使用i
和n
变量,然后不再使用它们。因此,它不会混淆那些阅读代码的人,关于变量的使用位置或它们的含义。
接下来,我们将介绍有关变量样式的一些注意事项。 样式是使用MixedCaps
或mixedCaps
而不是下划线用于多字名称。
传统风格 | 非传统风格 | 为什么非常规 |
---|---|---|
userName | user_name | 下划线不是传统的 |
i | index | i 更喜欢index 因为它更短 |
serveHTTP | serveHttp | 首字母缩略词应该大写 |
风格最重要的是要保持一致,并且你工作的团队同意这种风格。
正如“变量”一词所暗示的那样,我们可以很容易地改变Go变量。 这意味着我们可以通过重新分配将不同的值与先前分配的变量相连接。 能够重新分配是有用的,因为在整个程序过程中,我们可能需要将用户生成的值接受到已经初始化的变量中。 我们可能还需要将分配更改为先前定义的内容。
在处理其他人编写的大型程序时,知道我们可以轻松地重新分配变量可能很有用,并且不清楚已经定义了哪些变量。
让我们将76
的值赋给名为i
的int
类型的变量,然后为其赋值42
:
package main
import "fmt"
func main() {
i := 76
fmt.Println(i)
i = 42
fmt.Println(i)
}
76
42
这个例子表明我们可以先用整数值赋值变量i
,然后重新赋值变量i
,这次赋值为42
。
注意:声明和初始化变量时,可以使用:=
,但是,当您只想更改已声明的变量的值时,只需使用等于运算符( =
)。
因为Go是一种typed
语言,所以我们不能将一种类型分配给另一种类型。 例如,我们不能将值"Sammy"
赋值给int
类型的变量:
i := 72
i = "Sammy"
尝试为彼此分配不同的类型将导致编译时错误:
cannot use "Sammy" (type string) as type int in assignment
Go不允许我们多次使用变量名称:
var s string
var s string
s redeclared in this block
如果我们尝试对同一个变量名称多次使用短变量声明,我们也会收到编译错误。 这可能是错误的,因此了解错误消息的含义是有帮助的:
i := 5
i := 10
no new variables on left side of :=
与变量声明类似,考虑到变量的命名,将在您将来重新访问时为您和其他人提高程序的可读性。
Go还允许我们为同一行中的多个变量分配多个值。 这些值中的每一个都可以是不同的数据类型:
j, k, l := "shark", 2.05, 15
fmt.Println(j)
fmt.Println(k)
fmt.Println(l)
shark
2.05
15
在此示例中,变量j
分配给字符串"shark"
,变量k
分配给float 2.05
,变量l
分配给整数15
。
这种将多个变量分配给一行中的多个值的方法可以使代码中的行数保持不变。 但是,重要的是不要为了更少的代码行而牺牲可读性。
在程序中使用变量时,记住可变范围很重要。 变量的范围是指可从给定程序的代码中访问的特定位置。 这就是说,并非所有变量都可以从给定程序的所有部分访问 - 一些变量将是全局的,一些变量将是本地变量。
全局变量存在于函数之外。 函数中存在局部变量。
让我们看一下行动中的全局变量和局部变量:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
}
func main() {
printLocal()
fmt.Println(g)
}
local
global
这里我们使用var g = "global"
在函数外部创建一个全局变量。 然后我们定义函数printLocal()
。 在函数内部,分配一个名为l
的局部变量,然后打印出来。 程序通过调用printLocal()
然后打印全局变量g
。
因为g
是一个全局变量,我们可以在printLocal()
引用它。 让我们修改以前的程序来做到这一点:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
fmt.Println(g)
}
func main() {
printLocal()
fmt.Println(g)
}
local
global
global
我们首先声明一个全局变量g
, var g = "global"
。 在main
函数中,我们调用函数printLocal
,它声明一个局部变量l
并将其打印出来, fmt.Println(l)
。 然后, printLocal
打印出全局变量g
, fmt.Println(g)
。 即使g
未在printLocal
定义,仍然可以访问它,因为它是在全局范围内声明的。 最后, main
功能也打印出g
。
现在让我们尝试在函数外部调用局部变量:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
}
func main() {
fmt.Println(l)
}
undefined: l
我们不能在其指定的函数之外使用局部变量。如果您尝试这样做,编译时将收到undefined
错误。
让我们看另一个例子,我们对全局变量和局部变量使用相同的变量名:
package main
import "fmt"
var num1 = 5
func printNumbers() {
num1 := 10
num2 := 7
fmt.Println(num1)
fmt.Println(num2)
}
func main() {
printNumbers()
fmt.Println(num1)
}
10
7
5
在这个程序中,我们声明了num1
变量两次。 首先,我们在全局范围内声明num1
, var num1 = 5
,并再次在printNumbers
函数的本地范围内, num1 := 10
。 当我们从main
打印num1
,我们看到打印出的值为5
。 这是因为main
只能看到全局变量声明。 但是,当我们从printNumbers
函数打印出num1
时,它会看到本地声明,并将打印出值10
。 即使printNumbers
创建一个名为num1
的新变量并为其赋值10
,它也不会影响num1
的全局实例,值为5
。
使用变量时,还需要考虑程序的哪些部分需要访问每个变量; 相应地采用全局或局部变量。 在Go程序中,您会发现局部变量通常更常见。
常量就像变量,除非它们在声明后才能被修改。 常量对于定义将在程序中多次使用的值非常有用,但不应该更改。
例如,如果我们想要声明购物车系统的税率,我们可以使用常数,然后计算我们计划的不同区域的税。 在未来的某个时刻,如果税率发生变化,我们只需要在我们的计划中的一个位置更改该值。 如果我们使用变量,我们可能会意外地在程序中的某处更改值,这会导致计算不正确。
要声明常量,我们可以使用以下语法:
const shark = "Sammy"
fmt.Println(shark)
Sammy
如果我们在声明之后尝试修改常量,我们将得到一个编译时错误:
cannot assign to shark
常量可以是untyped
。 在处理整数类型数据等数字时,这非常有用。 如果常量是untyped
,则显式转换,其中typed
常量不是。 让我们看看我们如何使用常量:
package main
import "fmt"
const (
year = 365
leapYear = int32(366)
)
func main() {
hours := 24
minutes := int32(60)
fmt.Println(hours * year)
fmt.Println(minutes * year)
fmt.Println(minutes * leapYear)
}
8760
21900
21960
如果使用类型声明常量,则它将是精确类型。 这里当我们声明常量leapYear
,我们将其定义为数据类型int32
。 因此它是一个typed
常量,这意味着它只能使用int32
数据类型。 我们声明的year
常量没有类型,所以它被认为是untyped
。 因此,您可以将它与任何整数数据类型一起使用。
当定义hours
时,它推断它是int
类型,因为我们没有明确地给它一个类型, hours := 24
。 当我们声明minutes
,我们显式地将它声明为int32
, minutes := int32(60)
。
现在让我们来看看每个计算及其工作原理:
hours * year
在这种情况下, hours
是一个int
,而years
是无类型的 。 当程序编译时,它显式地将years
转换为int
,这允许乘法运算成功。
minutes * year
在这种情况下, minutes
是int32
,而year
是无类型的 。 当程序编译时,它显式地将years
转换为int32
,这允许乘法运算成功。
minutes * leapYear
在这种情况下, minutes
是int32
, leapYear
是int32
的类型常量。 编译器没有什么可以做的,因为两个变量已经是相同的类型。
如果我们尝试将两种类型和不兼容的类型相乘,程序将无法编译:
fmt.Println(hours * leapYear)
invalid operation: hours * leapYear (mismatched types int and int32)
在这种情况下,将hours
推断为int
,并将leapYear
显式声明为int32
。 因为Go是一种类型化语言,所以int
和int32
与数学运算不兼容。 要将它们相乘,您需要将一个转换为int32
或int
。
在本教程中,我们回顾了Go中变量的一些常见用例。 变量是编程的重要组成部分,用作代表我们在程序中使用的数据类型的值的符号。
Linux入门
QQ交流群:308781113(已满)