mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 03:34:15 +08:00
@@ -2,7 +2,7 @@
|
||||
|
||||
下面的例子中,main.go 使用了一个结构体,它来自 struct_pack 下的包 structPack。
|
||||
|
||||
示例 10.5 structPack.go:
|
||||
示例 10.5 [structPack.go](examples/chapter_10/struct_pack/structPack.go):
|
||||
|
||||
```go
|
||||
package structPack
|
||||
|
@@ -1,8 +1,8 @@
|
||||
# 10.4 带标签的结构体
|
||||
|
||||
结构体中的字段除了有名字和类型外,还可以有一个可选的标签(tag):它是一个附属于字段的字符串,可以是文档或其他的重要标记。标签的内容不可以在一般的编程中使用,只有包 `reflect` 能获取它。我们将在下一章(第 11.10 节)中深入的探讨 `reflect`包,它可以在运行时自省类型、属性和方法,比如:在一个变量上调用 `reflect.TypeOf()` 可以获取变量的正确类型,如果变量是一个结构体类型,就可以通过 Field 来索引结构体的字段,然后就可以使用 Tag 属性。
|
||||
结构体中的字段除了有名字和类型外,还可以有一个可选的标签(tag):它是一个附属于字段的字符串,可以是文档或其他的重要标记。标签的内容不可以在一般的编程中使用,只有包 `reflect` 能获取它。我们将在下一章(第 [11.10 节](11.10.md))中深入的探讨 `reflect`包,它可以在运行时自省类型、属性和方法,比如:在一个变量上调用 `reflect.TypeOf()` 可以获取变量的正确类型,如果变量是一个结构体类型,就可以通过 Field 来索引结构体的字段,然后就可以使用 Tag 属性。
|
||||
|
||||
示例 10.7 struct_tag.go:
|
||||
示例 10.7 [struct_tag.go](examples/chapter_10/struct_tag.go):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
考虑如下的程序:
|
||||
|
||||
示例 10.8 structs_anonymous_fields.go:
|
||||
示例 10.8 [structs_anonymous_fields.go](examples/chapter_10/structs_anonymous_fields.go):
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -64,7 +64,7 @@ func main() {
|
||||
|
||||
另外一个例子:
|
||||
|
||||
示例 10.9 embedd_struct.go:
|
||||
示例 10.9 [embedd_struct.go](examples/chapter_10/embedd_struct.go):
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -100,7 +100,7 @@ func main() {
|
||||
|
||||
当两个字段拥有相同的名字(可能是继承来的名字)时该怎么办呢?
|
||||
|
||||
1. 外层名字会覆盖内层名字(但是两者的内存空间都保留),这提供了一种重载字段或方法的方式
|
||||
1. 外层名字会覆盖内层名字(但是两者的内存空间都保留),这提供了一种重载字段或方法的方式;
|
||||
2. 如果相同的名字在同一级别出现了两次,如果这个名字被程序使用了,将会引发一个错误(不使用没关系)。没有办法来解决这种问题引起的二义性,必须由程序员自己修正。
|
||||
|
||||
例子:
|
||||
|
30
eBook/16.0.md
Normal file
30
eBook/16.0.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# 16 常见的陷阱与错误
|
||||
|
||||
在之前的内容中,有时候使用`!!...!!`标记警告go语言中的一些错误使用方式。当你在编程时候遇到的一个困难,可以确定本书特定的章节能找到类似的主题。为了方便起见,这里列出了一些常见陷进,以便于你能发现更多的解释和例子:
|
||||
|
||||
- 永远不要使用形如 `var p*a` 声明变量,这会混淆指针声明和乘法运算(参考[4.9小节](04.9.md))
|
||||
- 永远不要在`for`循环自身中改变计数器变量(参考[5.4小节](05.4.md))
|
||||
- 永远不要在`for-range`循环中使用一个值去改变自身的值(参考[5.4.4小节](05.4.md))
|
||||
- 永远不要将`goto`和前置标签一起使用(参考[5.6小节](05.6.md))
|
||||
- 永远不要忘记在函数名(参考[第6章](06.0.md))后加括号(),尤其调用一个对象的方法或者使用匿名函数启动一个协程时
|
||||
- 永远不要使用`new()`一个map,一直使用make(参考[第8章](08.0.md))
|
||||
- 当为一个类型定义一个String()方法时,不要使用`fmt.Print`或者类似的代码(参考[10.7小节](10.7.md))
|
||||
- 永远不要忘记当终止缓存写入时,使用`Flush`函数(参考[12.2.3小节](12.2.md))
|
||||
- 永远不要忽略错误提示,忽略错误会导致程序奔溃(参考[13.1小节](13.1.md))
|
||||
- 不要使用全局变量或者共享内存,这会使并发执行的代码变得不安全(参考[14.1小节](14.1.md))
|
||||
- `println`函数仅仅是用于调试的目的
|
||||
|
||||
最佳实践:对比以下使用方式:
|
||||
|
||||
- 使用正确的方式初始化一个元素是切片的映射,例如`map[type]slice`(参考[8.1.3小节](08.1.md))
|
||||
- 一直使用逗号,ok或者checked形式作为类型断言(参考[11.3小节](11.3.md))
|
||||
- 使用一个工厂函数创建并初始化自己定义类型(参考[10.2小节](10.2.md)-[18.4小节](18.4.md))
|
||||
- 仅当一个结构体的方法想改变结构体时,使用结构体指针作为方法的接受者,否则使用一个结构体值类型[10.6.3小节](10.6.md)
|
||||
|
||||
本章主要汇总了go语言使用过程中最常见的错误和注意事项。在之前的章节已经涉及到了完整的示例和解释,你应该做的不仅仅是阅读这段的标题。
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一章:[使用SMTP(简单邮件传输协议)发送邮件](15.12.md)
|
||||
- 下一节:[误用短声明导致变量覆盖](16.1.md)
|
41
eBook/16.1.md
Normal file
41
eBook/16.1.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# 16.1 误用短声明导致变量覆盖
|
||||
|
||||
```go
|
||||
var remember bool = false
|
||||
if something {
|
||||
remember := true //错误
|
||||
}
|
||||
// 使用remember
|
||||
```
|
||||
|
||||
在此代码段中,`remember`变量永远不会在`if`语句外面变成`true`,如果`something`为`true`,由于使用了短声明`:=`,`if`语句内部的新变量`remember`将覆盖外面的`remember`变量,并且该变量的值为`true`,但是在`if`语句外面,变量`remember`的值变成了`false`,所以正确的写法应该是:
|
||||
|
||||
```go
|
||||
if something {
|
||||
remember = true
|
||||
}
|
||||
```
|
||||
|
||||
此类型的错误也容易在`for`循环中出现,尤其当函数返回一个具名变量时难于察觉
|
||||
,例如以下的代码段:
|
||||
|
||||
```go
|
||||
func shadow() (err error) {
|
||||
x, err := check1() // x是新创建变量,err是被赋值
|
||||
if err != nil {
|
||||
return // 正确返回err
|
||||
}
|
||||
if y, err := check2(x); err != nil { // y和if语句中err被创建
|
||||
return // if语句中的err覆盖外面的err,所以错误的返回nil!
|
||||
} else {
|
||||
fmt.Println(y)
|
||||
}
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一节:[常见的陷阱与错误](16.0.md)
|
||||
- 下一节:[误用字符串](16.2.md)
|
@@ -4,7 +4,7 @@
|
||||
|
||||
```go
|
||||
str:="hello"
|
||||
c:=[]byte(s)
|
||||
c:=[]byte(str)
|
||||
c[0]='c'
|
||||
s2:= string(c) // s2 == "cello"
|
||||
```
|
||||
|
@@ -150,9 +150,21 @@
|
||||
|
||||
## 第四部分:实际应用
|
||||
|
||||
- 第16章:常见的陷阱与错误
|
||||
- 第16章:[常见的陷阱与错误](16.0.md)
|
||||
- 16.1 [误用短声明导致变量覆盖](16.1.md)
|
||||
- 第17章:模式
|
||||
- 第18章:[出于性能考虑的实用代码片段](18.0.md)
|
||||
- 18.1 [字符串](18.1.md)
|
||||
- 18.2 [数组和切片](18.2.md)
|
||||
- 18.3 [映射](18.3.md)
|
||||
- 18.4 [结构体](18.4.md)
|
||||
- 18.5 [接口](18.5.md)
|
||||
- 18.6 [函数](18.6.md)
|
||||
- 18.7 [文件](18.7.md)
|
||||
- 18.8 [协程(goroutine)与通道(channel)](18.8.md)
|
||||
- 18.9 [网络和网页应用](18.9.md)
|
||||
- 18.10 [其他](18.10.md)
|
||||
- 18.11 [出于性能考虑的最佳实践和建议](18.11.md)
|
||||
- 第19章:构建一个完整的应用程序
|
||||
- 第20章:Go 语言在 Google App Engine 的使用
|
||||
- 第21章:实际部署案例
|
||||
|
Reference in New Issue
Block a user