mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 00:43:26 +08:00
04.4.md
This commit is contained in:
@@ -1,17 +1,3 @@
|
||||
##啊哦,亲,你看得也太快了。。。还没翻译完呢 0 0
|
||||
要不等到 ***2013 年 4 月 25 日*** 再来看看吧~~
|
||||
|
||||
这里还有一些其它的学习资源噢~
|
||||
|
||||
- [《Go编程基础》](https://github.com/Unknwon/go-fundamental-programming):已更新至 [第9课](https://github.com/Unknwon/go-fundamental-programming/blob/master/lecture9/lecture9.md)
|
||||
- [《Go Web编程》](https://github.com/astaxie/build-web-application-with-golang)
|
||||
|
||||
神马?你说你不想学习?那好吧,去逛逛论坛看看行情也行~
|
||||
|
||||
- [Golang中文社区](http://bbs.mygolang.com/forum.php)
|
||||
- [Go语言学习园地](http://studygolang.com/)
|
||||
- [Golang中国](http://golang.tc)
|
||||
|
||||
#4.4 变量
|
||||
##4.4.1 简介
|
||||
声明变量的一般形式是使用 `var` 关键字:`var identifier type`。
|
||||
@@ -154,78 +140,77 @@ Example 4.5 [goos.go](examples/chapter_4/goos.go)
|
||||
|
||||
在 Go 语言中,指针(第 4.9 节)属于引用类型,其它的引用类型还包括 slices(第 7 章),maps(第 8 章)和 channel(第 13 章)。被引用的变量会存储在堆中,以便进行垃圾回收,且比栈拥有更大的内存空间。
|
||||
|
||||
## 4.4.3 打印CHECK
|
||||
|
||||
函数 Printf 在 fmt 包外也是可见的,因为它以大写字母 P 开头,主要用于打印输出到控制台。通常使用的格式化字符串作为第一个参数:
|
||||
## 4.4.3 打印
|
||||
函数 `Printf` 可以在 fmt 包外部使用,这是因为它以大写字母 P 开头,该函数主要用于打印输出到控制台。通常使用的格式化字符串作为第一个参数:
|
||||
|
||||
func Printf(format string, list of variables to be printed)
|
||||
|
||||
在 Listing 4.5 中,格式化字符串为: **"The operating system is: %s\n"**
|
||||
在 Example 4.5 中,格式化字符串为:`"The operating system is: %s\n"`。
|
||||
|
||||
这个格式化字符串含有一个或更多的格式化标识符 `%..`, `..` 表示可以替换不同的值,如 **%s** 代表一个字符串值。**%v** 标识默认的格式化标识符。这些标识符的值从逗号之后顺序排列,如果有超过1个,它们之间用逗号分隔。这些 % 占位符的格式可以精细控制。
|
||||
这个格式化字符串可以含有一个或多个的格式化标识符,例如:`%..`,其中 `..` 可以被不同类型所对应的标识符替换,如 `%s` 代表字符串标识符、`%v` 代表使用类型的默认输出格式的标识符。这些标识符所对应的值从格式化字符串后的第一个逗号开始按照相同顺序添加,如果参数超过 1 个则同样需要使用逗号分隔。使用这些占位符可以很好地控制格式化输出的文本。
|
||||
|
||||
函数 **fmt.Sprintf** 与 **Printf** 的行为完全相同。但是只简单的返回格式化后的字符串:所以可以在你的程序中使用字符串包含变量值使用(例子,见 Listing 15.4-simple_tcp_server.go)。
|
||||
函数 `fmt.Sprintf` 与 `Printf` 的作用是完全相同的,不过前者将格式化后的字符串以返回值的形式返回给调用者,因此你可以在程序中使用包含变量的字符串,具体例子可以参见 Example 15.4 [simple_tcp_server.go](examples/chapter_15/simple_tcp_server.go)。
|
||||
|
||||
函数 **fmt.Print** 和 **fmt.Println** 表现完全自动化使用格式化标识符 **%v** 进行格式化,在每个参数后添加空格,后者在最后添加一个换行符。所以 **fmt.Print("Hello:", 23)** 将输出:**Hello: 23**
|
||||
函数 `fmt.Print` 和 `fmt.Println` 会自动使用格式化标识符 `%v` 对字符串进行格式化,两者都会在每个参数之间自动增加空格,而后者还会在字符串的最后加上一个换行符。例如:`fmt.Print("Hello:", 23)` 将输出:`Hello: 23`。
|
||||
|
||||
## 4.4.4 简短形式,使用 := 赋值操作符
|
||||
##4.4.4 简短形式,使用 := 赋值操作符
|
||||
我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,而这个时候再在 Example 4.4.1 的最后一个声明语句写上 `var` 关键字就显得有些多余了,因此我们可以将它们简写为 `a := 50` 或 `b := false`。
|
||||
|
||||
忽略类型,关键字 var 在 § 4.4.1 最后一段中是非常多于的,我们可以简写为:**a := 50** 或 **b := false**。
|
||||
a 和 b 的类型(int 和 bool)将由编译器自动推断。
|
||||
|
||||
a 和 b 的类型(int 和 bool)将被编译器推断出。
|
||||
这是使用变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值。使用操作符 `:=` 可以高效地创建一个新的变量,称之为初始化声明。
|
||||
|
||||
这是首选形式,但它只能在*函数内部使用,而不是在包的范围*。 操作符 := 将有效地创建一个新的变量,它也被称为初始化声明。
|
||||
**注意事项**
|
||||
|
||||
*提醒*:如果在这行之后写相同的代码块,如我们声明 a := 20,这是不允许的:编译器会给出错误提示 “**no new variables on left side of :=**”;但 a = 20 是可以的,因为这是给相同的变量一个新的值。
|
||||
如果在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如:`a := 20` 就是不被允许的,编译器会提示错误 `no new variables on left side of :=`,但是 `a = 20` 是可以的,因为这是给相同的变量赋予一个新的值。
|
||||
|
||||
一个变量 a 被使用,但是没有定义,会得到一个编译错误:**undefined: a**
|
||||
如果你在定义变量 a 之前使用它,则会得到编译错误 `undefined: a`。
|
||||
|
||||
声明一个*本地*变量,但是不使用它,也会得到编译错误;如变量 a 在如下的 main 函数中:
|
||||
如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,例如下面这个例子当中的变量 a:
|
||||
|
||||
func main() {
|
||||
var a string = "abc"
|
||||
fmt.Println(“hello, world”)
|
||||
}
|
||||
|
||||
将得到错误:**a declared and not used**
|
||||
尝试编译这段代码将得到错误 `a declared and not used`。
|
||||
|
||||
当然,设置 a 的值也不是足够的,这个值必须被使用,所以 **fmt.Println("hello, world", a)** 会移除错误。
|
||||
此外,单纯地给 a 赋值也是不够的,这个值必须被使用,所以使用 `fmt.Println("hello, world", a)` 会移除错误。
|
||||
|
||||
但是全局变量是允许这样的。
|
||||
但是全局变量是允许声明但不使用。
|
||||
|
||||
其他的简短形式为:
|
||||
|
||||
同一类型的多个变量可以声明在一行,如:**var a, b, c int**
|
||||
同一类型的多个变量可以声明在同一行,如:`var a, b, c int`。
|
||||
|
||||
(这是类型写在标识符后面的重要原因)
|
||||
(这是将类型写在标识符后面的一个重要原因)
|
||||
|
||||
多变量可以在同一行进行赋值,如:**a, b, c = 5, 7, "abc"**
|
||||
多变量可以在同一行进行赋值,如:`a, b, c = 5, 7, "abc"`。
|
||||
|
||||
这假设了变量 a,b 和 c 都被声明了,否则应这样:**a, b, c := 5, 7, "abc"**
|
||||
上面这行假设了变量 a,b 和 c 都已经被声明,否则的话应该这样使用:`a, b, c := 5, 7, "abc"`。
|
||||
|
||||
右边的这些值以相同的顺序赋值给左边的变量,所以 a 的值是 5, b 的值是 7,c 的值是 "abc"。
|
||||
右边的这些值以相同的顺序赋值给左边的变量,所以 a 的值是 `5`, b 的值是 `7`,c 的值是 `"abc"`。
|
||||
|
||||
这被称为*并行或同时赋值*。
|
||||
这被称为 **并行** 或 **同时** 赋值。
|
||||
|
||||
使用两个变量,它可以被用来执行交换的值:**a, b = b, a**
|
||||
如果你想要交换两个变量的值,则可以简单地使用 `a, b = b, a`。
|
||||
|
||||
(在 Go 语言,这样省去了使用交换函数的必要)
|
||||
(在 Go 语言中,这样省去了使用交换函数的必要)
|
||||
|
||||
空标识符 _ 也被用于扔掉值,如值 5 在:**_, b = 5, 7** 被扔掉。
|
||||
空白标识符 `_` 也被用于抛弃值,如值 `5` 在:`_, b = 5, 7` 中被抛弃。
|
||||
|
||||
_ 实际上是一个只写变量,你不能得到它的值。这样做是因为一个声明的变量必须在 Go 语言中必须被使用,但有时你并不需要使用从一个函数得到的所有返回值。
|
||||
`_` 实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。
|
||||
|
||||
多赋值也被用于当一个函数返回多于一个值,如这里 val 和一个错误 err 被 Func1 这个函数返回:**val, err = Func1(var1)**
|
||||
并行赋值也被用于当一个函数返回多个返回值时,比如这里的 `val` 和错误 `err` 是通过调用 `Func1` 函数同时得到:`val, err = Func1(var1)`。
|
||||
|
||||
## 4.4.5 初始函数
|
||||
##4.4.5 init 函数
|
||||
变量除了可以在全局声明中初始化,也可以在 init() 函数中初始化。这是一类非常特殊的函数,它不能够被人为调用,而是在每个包完成初始化后自动执行,并且执行优先级在 main() 函数高。
|
||||
|
||||
除了在全局声明中初始化,变量也可以在一个 init() 函数中初始化。这是一个特殊的函数名称 init(),它不能被调用,但在 package main 中自动在 main() 函数之前,或者自动在导入含有该函数的包之前执行。
|
||||
每一个源文件都可以包含且只包含一个 init() 函数。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。
|
||||
|
||||
每一个源文件都可以包含且只包含一个 init() 方法。初始化总是单线程的,并且包依赖关系保证其正确的执行顺序。
|
||||
一个可能的用途是在开始执行程序之前对数据进行检验或修复,以保证程序状态的正确性。
|
||||
|
||||
一个可能的用途是在真正执行之前,检验或修复程序状态的正确性。
|
||||
|
||||
例子: Listing 4.6—[init.go](examples/chapter_4/init.go):
|
||||
Example 4.6 [init.go](examples/chapter_4/init.go):
|
||||
|
||||
package trans
|
||||
import "math"
|
||||
@@ -234,9 +219,9 @@ _ 实际上是一个只写变量,你不能得到它的值。这样做是因为
|
||||
Pi = 4 * math.Atan(1) // init() function computes Pi
|
||||
}
|
||||
|
||||
在它的 init() 函数中,变量 Pi 被计算初始值。
|
||||
在它的 init() 函数中计算变量 Pi 的初始值。
|
||||
|
||||
程序在 Listing 4.7 [user_init.go](examples/chapter_4/user_init.go) 中导入了包 trans (在相同的路径中) 并且使用 Pi:
|
||||
Example 4.7 [user_init.go](examples/chapter_4/user_init.go) 中导入了包 trans(在相同的路径中)并且使用到了变量 Pi:
|
||||
|
||||
package main
|
||||
import (
|
||||
@@ -248,16 +233,16 @@ _ 实际上是一个只写变量,你不能得到它的值。这样做是因为
|
||||
fmt.Printf("2*Pi = %g\n", twoPi) // 2*Pi = 6.283185307179586
|
||||
}
|
||||
|
||||
init() 函数也经常被用在当一个程序开始之前,一个 backend() goroutine 需要被执行,如:
|
||||
init() 函数也经常被用在当一个程序开始之前调用后台执行的 goroutine,如下面这个例子当中的 `backend()`:
|
||||
|
||||
func init() {
|
||||
// setup preparations
|
||||
go backend()
|
||||
}
|
||||
|
||||
*练习*:推断以下程序的输出,并解释你的答案,然后编译并执行它们。
|
||||
**练习** 推断以下程序的输出,并解释你的答案,然后编译并执行它们。
|
||||
|
||||
练习 4.1: [local_scope.go](examples/chapter_4/local_scope.go):
|
||||
练习 4.1 [local_scope.go](examples/chapter_4/local_scope.go):
|
||||
|
||||
package main
|
||||
var a = "G"
|
||||
@@ -272,7 +257,7 @@ init() 函数也经常被用在当一个程序开始之前,一个 backend() go
|
||||
print(a)
|
||||
}
|
||||
|
||||
练习 4.2: [global_scope.go](examples/chapter_4/global_scope.go):
|
||||
练习 4.2 [global_scope.go](examples/chapter_4/global_scope.go):
|
||||
|
||||
package main
|
||||
var a = "G"
|
||||
@@ -289,7 +274,7 @@ init() 函数也经常被用在当一个程序开始之前,一个 backend() go
|
||||
print(a)
|
||||
}
|
||||
|
||||
练习 4.3: [function_calls_function.go](examples/chapter_4/function_calls_function.go)
|
||||
练习 4.3 [function_calls_function.go](examples/chapter_4/function_calls_function.go)
|
||||
|
||||
package main
|
||||
var a string
|
||||
@@ -307,7 +292,6 @@ init() 函数也经常被用在当一个程序开始之前,一个 backend() go
|
||||
print(a)
|
||||
}
|
||||
|
||||
|
||||
##链接
|
||||
- [目录](directory.md)
|
||||
- 上一节:[常量](04.3.md)
|
||||
|
Reference in New Issue
Block a user