mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-19 03:50:11 +08:00
Merge remote-tracking branch 'bob/master'
This commit is contained in:
@@ -474,7 +474,7 @@ var ch byte = 65 或 var ch byte = '\x41'
|
||||
|
||||
(`\x` 总是紧跟着长度为 2 的 16 进制数)
|
||||
|
||||
另外一种可能的写法是 `\` 后面紧跟着长度为 3 的十进制数,例如:`\377`。
|
||||
另外一种可能的写法是 `\` 后面紧跟着长度为 3 的八进制数,例如:`\377`。
|
||||
|
||||
不过 Go 同样支持 Unicode(UTF-8),因此字符同样称为 Unicode 代码点或者 runes,并在内存中使用 int 来表示。在文档中,一般使用格式 U+hhhh 来表示,其中 h 表示一个 16 进制数。其实 `rune` 也是 Go 当中的一个类型,并且是 `int32` 的别名。
|
||||
|
||||
|
@@ -27,14 +27,14 @@ package main
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
x := Min(1, 3, 2, 0)
|
||||
x := min(1, 3, 2, 0)
|
||||
fmt.Printf("The minimum is: %d\n", x)
|
||||
arr := []int{7,9,3,5,1}
|
||||
x = Min(arr...)
|
||||
x = min(arr...)
|
||||
fmt.Printf("The minimum in the array arr is: %d", x)
|
||||
}
|
||||
|
||||
func Min(a ...int) int {
|
||||
func min(a ...int) int {
|
||||
if len(a)==0 {
|
||||
return 0
|
||||
}
|
||||
|
@@ -11,17 +11,17 @@ package main
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
Function1()
|
||||
function1()
|
||||
}
|
||||
|
||||
func Function1() {
|
||||
fmt.Printf("In Function1 at the top\n")
|
||||
defer Function2()
|
||||
fmt.Printf("In Function1 at the bottom!\n")
|
||||
func function1() {
|
||||
fmt.Printf("In function1 at the top\n")
|
||||
defer function2()
|
||||
fmt.Printf("In function1 at the bottom!\n")
|
||||
}
|
||||
|
||||
func Function2() {
|
||||
fmt.Printf("Function2: Deferred until the end of the calling function!")
|
||||
func function2() {
|
||||
fmt.Printf("function2: Deferred until the end of the calling function!")
|
||||
}
|
||||
```
|
||||
|
||||
|
@@ -121,7 +121,7 @@ func sum(a []int) int {
|
||||
return s
|
||||
}
|
||||
|
||||
func main {
|
||||
func main() {
|
||||
var arr = [5]int{0, 1, 2, 3, 4}
|
||||
sum(arr[:])
|
||||
}
|
||||
@@ -226,7 +226,7 @@ v := make([]int, 10, 50)
|
||||
这样分配一个有 50 个 int 值的数组,并且创建了一个长度为 10,容量为 50 的 切片 v,该 切片 指向数组的前 10 个元素。
|
||||
|
||||
**问题 7.3** 给定 `s := make([]byte, 5)`,len(s) 和 cap(s) 分别是多少?`s = s[2:4]`,len(s) 和 cap(s) 又分别是多少?
|
||||
**问题 7.4** 假设 `s1 := []byte{'p', 'o', 'e', 'm'}` 且 `s2 := d[2:]`,s2 的值是多少?如果我们执行 `s2[1] == 't'`,s1 和 s2 现在的值又分配是多少?
|
||||
**问题 7.4** 假设 `s1 := []byte{'p', 'o', 'e', 'm'}` 且 `s2 := s1[2:]`,s2 的值是多少?如果我们执行 `s2[1] = 't'`,s1 和 s2 现在的值又分别是多少?
|
||||
|
||||
## 7.2.5 多维 切片
|
||||
|
||||
|
@@ -44,7 +44,7 @@ func AppendByte(slice []byte, data ...byte) []byte {
|
||||
}
|
||||
```
|
||||
|
||||
`func copy(dst, src []T) int` copy 方法将类型为 T 的切片从源地址 src 拷贝到目标地址 dst,覆盖 dst 的相关元素,并且返回拷贝的元素个数。源地址和目标地址可能会有重叠。拷贝个数是 src 和 dst 的长度最小值。如果 src 是字符串那么元素类型就是 byte。如果你还想继续使用 src,在拷贝技术后执行 `src = dst`。
|
||||
`func copy(dst, src []T) int` copy 方法将类型为 T 的切片从源地址 src 拷贝到目标地址 dst,覆盖 dst 的相关元素,并且返回拷贝的元素个数。源地址和目标地址可能会有重叠。拷贝个数是 src 和 dst 的长度最小值。如果 src 是字符串那么元素类型就是 byte。如果你还想继续使用 src,在拷贝结束后执行 `src = dst`。
|
||||
|
||||
**练习 7.9**
|
||||
|
||||
|
@@ -27,7 +27,7 @@ map 也可以用函数作为自己的值,这样就可以用来做分支结构
|
||||
|
||||
key1 对应的值可以通过赋值符号来设置为 `val1:map1[key1] = val1`。
|
||||
|
||||
令 `v: = map1[key1]` 可以将 key1 对应的值赋值为 v;如果 map 中没有 key1 存在,那么 v 将被赋值为 map1 的值类型的空值。
|
||||
令 `v := map1[key1]` 可以将 key1 对应的值赋值为 v;如果 map 中没有 key1 存在,那么 v 将被赋值为 map1 的值类型的空值。
|
||||
|
||||
常用的 `len(map1)` 方法可以获得 map 中的 pair 数目,这个数目是可以伸缩的,因为 map-pairs 在运行时可以动态添加和删除。
|
||||
|
||||
|
@@ -53,7 +53,7 @@ func main() {
|
||||
但是如果你想要一个排序的列表你最好使用结构体切片,这样会更有效:
|
||||
|
||||
```go
|
||||
type struct {
|
||||
type name struct {
|
||||
key string
|
||||
value int
|
||||
}
|
||||
|
@@ -26,7 +26,6 @@ func main() {
|
||||
for k, v := range invMap {
|
||||
fmt.Printf("Key: %v, Value: %v / ", k, v)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
```
|
||||
|
||||
|
0
eBook/09.5.md
Executable file → Normal file
0
eBook/09.5.md
Executable file → Normal file
0
eBook/09.8.md
Executable file → Normal file
0
eBook/09.8.md
Executable file → Normal file
@@ -7,7 +7,11 @@ Go 开发者不需要写代码来释放程序中不再使用的变量和结构
|
||||
如果想知道当前的内存状态,可以使用:
|
||||
|
||||
```go
|
||||
fmt.Printf("%d\n", runtime.MemStats.Alloc/1024)
|
||||
// fmt.Printf("%d\n", runtime.MemStats.Alloc/1024)
|
||||
// 此处代码在 Go 1.5.1下不再有效,更正为
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
fmt.Printf("%d Kb\n", m.Alloc / 1024)
|
||||
```
|
||||
|
||||
上面的程序会给出已分配内存的总量,单位是 Kb。进一步的测量参考 [文档页面](http://golang.org/pkg/runtime/#MemStatsType)。
|
||||
@@ -30,4 +34,4 @@ runtime.SetFinalizer(obj, func(obj *typeObj))
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一节:[类型的 String() 方法和格式化描述符](10.7.md)
|
||||
- 下一章:[接口(Interfaces)与反射(reflection)](11.0.md)
|
||||
- 下一章:[接口(Interfaces)与反射(reflection)](11.0.md)
|
||||
|
68
eBook/11.11.md
Normal file
68
eBook/11.11.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# 11.11 Printf和反射
|
||||
|
||||
在Go语言的标准库中,前几节所述的反射的功能被大量地使用。举个例子,fmt包中的Printf(以及其他格式化输出函数)都会使用反射来分析它的`...`参数。
|
||||
|
||||
Printf的函数声明为:
|
||||
|
||||
```go
|
||||
func Printf(format string, args ... interface{}) (n int, err error)
|
||||
```
|
||||
|
||||
Printf中的`...`参数为空接口类型。Printf使用反射包来解析这个参数列表。所以,Printf能够知道它每个参数的类型。因此格式化字符串中只有%d而没有%u和%ld,因为它知道这个参数是unsigned还是long。这也是为什么Print和Println在没有格式字符串的情况下还能如此漂亮地输出。
|
||||
|
||||
为了让大家更加具体地了解Printf中的反射,我们实现了一个简单的通用输出函数。其中使用了type-switch来推导参数类型,并根据类型来输出每个参数的值(这里用了10.7节中练习10.13的部分代码)
|
||||
|
||||
示例 11.15 print.go:
|
||||
```go
|
||||
// print.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
type Celsius float64
|
||||
|
||||
func (c Celsius) String() string {
|
||||
return strconv.FormatFloat(float64(c),'f', 1, 64) + " °C"
|
||||
}
|
||||
|
||||
type Day int
|
||||
|
||||
var dayName = []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
|
||||
|
||||
func (day Day) String() string {
|
||||
return dayName[day]
|
||||
}
|
||||
|
||||
func print(args ...interface{}) {
|
||||
for i, arg := range args {
|
||||
if i > 0 {os.Stdout.WriteString(" ")}
|
||||
switch a := arg.(type) { // type switch
|
||||
case Stringer: os.Stdout.WriteString(a.String())
|
||||
case int: os.Stdout.WriteString(strconv.Itoa(a))
|
||||
case string: os.Stdout.WriteString(a)
|
||||
// more types
|
||||
default: os.Stdout.WriteString("???")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
print(Day(1), "was", Celsius(18.36)) // Tuesday was 18.4 °C
|
||||
}
|
||||
// Tuesday was 18.4 °C
|
||||
```
|
||||
|
||||
在12.8节中我们将阐释fmt.Fprintf()是怎么运用同样的反射原则的。
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一节:[反射包](11.10.md)
|
||||
- 下一节:[接口和动态类型](11.12.md)
|
79
eBook/12.6.md
Normal file
79
eBook/12.6.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# 用切片读写文件
|
||||
|
||||
切片提供了标准的Go方法来处理I/O缓冲,下面`cat`函数的第二版中,在一个切片缓冲内使用无线for循环(直到文件尾部EOF)读取文件,并写入到标准输出。
|
||||
|
||||
```go
|
||||
func cat(f *os.File) {
|
||||
const NBUF = 512
|
||||
var buf [NBUF]byte
|
||||
for {
|
||||
switch nr, err := f.Read(buf[:]); true {
|
||||
case nr < 0:
|
||||
fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
case nr == 0: // EOF
|
||||
return
|
||||
case nr > 0:
|
||||
if nw, ew := os.Stdout.Write(buf[0:nr]); nw != nr {
|
||||
fmt.Fprintf(os.Stderr, "cat: error writing: %s\n", ew.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
代码来自于`cat2.go`,使用了os包中的`os.file`和`Read`方法;`cat2.go`与`cat.go`具有同样的功能。
|
||||
|
||||
|
||||
示例 12.14 [cat2.go](examples/chapter_12/cat2.go):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func cat(f *os.File) {
|
||||
const NBUF = 512
|
||||
var buf [NBUF]byte
|
||||
for {
|
||||
switch nr, err := f.Read(buf[:]); true {
|
||||
case nr < 0:
|
||||
fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
case nr == 0: // EOF
|
||||
return
|
||||
case nr > 0:
|
||||
if nw, ew := os.Stdout.Write(buf[0:nr]); nw != nr {
|
||||
fmt.Fprintf(os.Stderr, "cat: error writing: %s\n", ew.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse() // Scans the arg list and sets up flags
|
||||
if flag.NArg() == 0 {
|
||||
cat(os.Stdin)
|
||||
}
|
||||
for i := 0; i < flag.NArg(); i++ {
|
||||
f, err := os.Open(flag.Arg(i))
|
||||
if f == nil {
|
||||
fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cat(f)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一节:[用buffer读取文件](12.5.md)
|
||||
- 下一节:[用defer关闭文件](12.7.md)
|
Reference in New Issue
Block a user