Skip to content

Commit

Permalink
fmt code
Browse files Browse the repository at this point in the history
  • Loading branch information
chai2010 committed Dec 17, 2018
1 parent 8c25545 commit 9ad62fe
Show file tree
Hide file tree
Showing 18 changed files with 174 additions and 133 deletions.
31 changes: 17 additions & 14 deletions ch1-basic/ch1-03-array-string-and-slice.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ Go语言中数组、字符串和切片三者是密切相关的数据结构。这
我们先看看数组有哪些定义方式:

```go
var a [3]int // 定义一个长度为3的int类型数组, 元素全部为0
var b = [...]int{1, 2, 3} // 定义一个长度为3的int类型数组, 元素为 1, 2, 3
var c = [...]int{2: 3, 1: 2} // 定义一个长度为3的int类型数组, 元素为 0, 2, 3
var d = [...]int{1, 2, 4: 5, 6} // 定义一个长度为6的int类型数组, 元素为 1, 2, 0, 0, 5, 6
var a [3]int // 定义长度为3的int型数组, 元素全部为0
var b = [...]int{1, 2, 3} // 定义长度为3的int型数组, 元素为 1, 2, 3
var c = [...]int{2: 3, 1: 2} // 定义长度为3的int型数组, 元素为 0, 2, 3
var d = [...]int{1, 2, 4: 5, 6} // 定义长度为6的int型数组, 元素为 1, 2, 0, 0, 5, 6
```

第一种方式是定义一个数组变量的最基本的方式,数组的长度明确指定,数组中的每个元素都以零值初始化。
Expand Down Expand Up @@ -169,7 +169,9 @@ type StringHeader struct {
分析可以发现,“Hello, world”字符串底层数据和以下数组是完全一致的:

```go
var data = [...]byte{'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd'}
var data = [...]byte{
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd',
}
```

字符串虽然不是切片,但是支持切片操作,不同位置的切片底层也访问的同一块内存数据(因为字符串是只读的,相同的字符串面值常量通常是对应同一个字符串常量):
Expand Down Expand Up @@ -202,7 +204,8 @@ fmt.Printf("%#v\n", []byte("Hello, 世界"))
输出的结果是:

```go
[]byte{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c}
[]byte{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0xe4, 0xb8, 0x96, 0xe7, \
0x95, 0x8c}
```

分析可以发现`0xe4, 0xb8, 0x96`对应中文“世”,`0xe7, 0x95, 0x8c`对应中文“界”。我们也可以在字符串面值中直指定UTF8编码后的值(源文件中全部是ASCII码,可以避免出现多字节的字符)。
Expand Down Expand Up @@ -276,7 +279,7 @@ fmt.Printf("%#v\n", string([]rune{'世', '界'})) // 世界
```go
func forOnString(s string, forBody func(i int, r rune)) {
for i := 0; len(s) > 0; {
r, size := utf8.DecodeRuneInString(s)
r, size := utf8.DecodeRuneInString(s)
forBody(i, r)
s = s[size:]
i += size
Expand Down Expand Up @@ -360,9 +363,9 @@ func runes2string(s []int32) string {

```go
type SliceHeader struct {
Data uintptr
Len int
Cap int
Data uintptr
Len int
Cap int
}
```

Expand Down Expand Up @@ -555,8 +558,8 @@ func Filter(s []byte, fn func(x byte) bool) []byte {

```go
func FindPhoneNumber(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
return regexp.MustCompile("[0-9]+").Find(b)
b, _ := ioutil.ReadFile(filename)
return regexp.MustCompile("[0-9]+").Find(b)
}
```

Expand All @@ -566,8 +569,8 @@ func FindPhoneNumber(filename string) []byte {

```go
func FindPhoneNumber(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
b = regexp.MustCompile("[0-9]+").Find(b)
b, _ := ioutil.ReadFile(filename)
b = regexp.MustCompile("[0-9]+").Find(b)
return append([]byte{}, b...)
}
```
Expand Down
45 changes: 23 additions & 22 deletions ch1-basic/ch1-04-func-method-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ func (s UpperString) String() string {
}

type fmt.Stringer interface {
String() string
String() string
}

func main() {
Expand All @@ -384,24 +384,24 @@ Go语言中,对于基础类型(非接口类型)不支持隐式的转换,

```go
var (
a io.ReadCloser = (*os.File)(f) // 隐式转换, *os.File 类型满足了 io.ReadCloser 接口
b io.Reader = a // 隐式转换, io.ReadCloser 满足了 io.Reader 接口
c io.Closer = a // 隐式转换, io.ReadCloser 满足了 io.Closer 接口
d io.Reader = c.(io.Reader) // 显式转换, io.Closer 并不显式满足 io.Reader 接口
a io.ReadCloser = (*os.File)(f) // 隐式转换, *os.File 满足 io.ReadCloser 接口
b io.Reader = a // 隐式转换, io.ReadCloser 满足 io.Reader 接口
c io.Closer = a // 隐式转换, io.ReadCloser 满足 io.Closer 接口
d io.Reader = c.(io.Reader) // 显式转换, io.Closer 不满足 io.Reader 接口
)
```

有时候对象和接口之间太灵活了,导致我们需要人为地限制这种无意之间的适配。常见的做法是定义一个含特殊方法来区分接口。比如`runtime`包中的`Error`接口就定义了一个特有的`RuntimeError`方法,用于避免其它类型无意中适配了该接口:

```go
type runtime.Error interface {
error
error

// RuntimeError is a no-op function but
// serves to distinguish types that are run time
// errors from ordinary errors: a type is a
// run time error if it has a RuntimeError method.
RuntimeError()
// RuntimeError is a no-op function but
// serves to distinguish types that are run time
// errors from ordinary errors: a type is a
// run time error if it has a RuntimeError method.
RuntimeError()
}
```

Expand Down Expand Up @@ -485,17 +485,18 @@ func (p *grpcPlugin) GenerateImports(file *generator.FileDescriptor) {

```go
type Plugin interface {
// Name identifies the plugin.
Name() string
// Init is called once after data structures are built but before
// code generation begins.
Init(g *Generator)
// Generate produces the code generated by the plugin for this file,
// except for the imports, by calling the generator's methods P, In, and Out.
Generate(file *FileDescriptor)
// GenerateImports produces the import declarations for this file.
// It is called after Generate.
GenerateImports(file *FileDescriptor)
// Name identifies the plugin.
Name() string
// Init is called once after data structures are built but before
// code generation begins.
Init(g *Generator)
// Generate produces the code generated by the plugin for this file,
// except for the imports, by calling the generator's methods
// P, In, and Out.
Generate(file *FileDescriptor)
// GenerateImports produces the import declarations for this file.
// It is called after Generate.
GenerateImports(file *FileDescriptor)
}
```

Expand Down
42 changes: 21 additions & 21 deletions ch1-basic/ch1-05-mem.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,18 @@ var (
)

func Instance() *singleton {
if atomic.LoadUint32(&initialized) == 1 {
if atomic.LoadUint32(&initialized) == 1 {
return instance
}

mu.Lock()
defer mu.Unlock()
mu.Lock()
defer mu.Unlock()

if instance == nil {
if instance == nil {
defer atomic.StoreUint32(&initialized, 1)
instance = &singleton{}
}
return instance
instance = &singleton{}
}
return instance
}
```

Expand Down Expand Up @@ -145,10 +145,10 @@ var (
)

func Instance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
once.Do(func() {
instance = &singleton{}
})
return instance
}
```

Expand All @@ -162,20 +162,20 @@ config.Store(loadConfig())

// 启动一个后台线程, 加载更新后的配置信息
go func() {
for {
time.Sleep(time.Second)
config.Store(loadConfig())
}
for {
time.Sleep(time.Second)
config.Store(loadConfig())
}
}()

// 用于处理请求的工作者线程始终采用最新的配置信息
for i := 0; i < 10; i++ {
go func() {
for r := range requests() {
c := config.Load()
// ...
}
}()
go func() {
for r := range requests() {
c := config.Load()
// ...
}
}()
}
```

Expand Down
20 changes: 11 additions & 9 deletions ch1-basic/ch1-06-goroutine.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,9 @@ func (p *Publisher) Close() {
}

// 发送主题,可以容忍一定的超时
func (p *Publisher) sendTopic(sub subscriber, topic topicFunc, v interface{}, wg *sync.WaitGroup) {
func (p *Publisher) sendTopic(
sub subscriber, topic topicFunc, v interface{}, wg *sync.WaitGroup,
) {
defer wg.Done()
if topic != nil && !topic(v) {
return
Expand Down Expand Up @@ -343,14 +345,14 @@ func main() {
var limit = make(chan int, 3)

func main() {
for _, w := range work {
go func() {
limit <- 1
w()
<-limit
}()
}
select{}
for _, w := range work {
go func() {
limit <- 1
w()
<-limit
}()
}
select{}
}
```

Expand Down
24 changes: 12 additions & 12 deletions ch1-basic/ch1-07-error-and-panic.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ func CopyFile(dstName, srcName string) (written int64, err error) {

```go
func ParseJSON(input string) (s *Syntax, err error) {
defer func() {
if p := recover(); p != nil {
err = fmt.Errorf("JSON: internal error: %v", p)
}
}()
// ...parser...
defer func() {
if p := recover(); p != nil {
err = fmt.Errorf("JSON: internal error: %v", p)
}
}()
// ...parser...
}
```

Expand All @@ -113,7 +113,7 @@ Go语言库的实现习惯: 即使在包内部使用了`panic`,但是在导出

```go
if _, err := html.Parse(resp.Body); err != nil {
return nil, fmt.Errorf("parsing %s as HTML: %v", url,err)
return nil, fmt.Errorf("parsing %s as HTML: %v", url,err)
}
```

Expand Down Expand Up @@ -193,9 +193,9 @@ func main() {
上面的例子中,错误被进行了2层包装。我们可以这样遍历原始错误经历了哪些包装流程:

```go
for i, e := range err.(errors.Error).Wraped() {
fmt.Printf("wraped(%d): %v\n", i, e)
}
for i, e := range err.(errors.Error).Wraped() {
fmt.Printf("wraped(%d): %v\n", i, e)
}
```

同时也可以获取每个包装错误的函数调用堆栈信息:
Expand Down Expand Up @@ -238,7 +238,7 @@ fmt.Println(err.(errors.Error).Code())
```go
f, err := os.Open("filename.ext")
if err != nil {
// 失败的情形, 马上返回错误
// 失败的情形, 马上返回错误
}

// 正常的处理流程
Expand Down Expand Up @@ -422,7 +422,7 @@ func main {
}
}()

...
// ...
}
```

Expand Down
6 changes: 3 additions & 3 deletions ch2-cgo/ch2-02-basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ package main
#include <stdio.h>
void printint(int v) {
printf("printint: %d\n", v);
printf("printint: %d\n", v);
}
*/
import "C"

func main() {
v := 42
C.printint(C.int(v))
v := 42
C.printint(C.int(v))
}
```

Expand Down
10 changes: 6 additions & 4 deletions ch2-cgo/ch2-07-memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,15 @@ panic: runtime error: cgo result has Go pointer
goroutine 1 [running]:
main._cgoexpwrap_cfb3840e3af2_getGoPtr.func1(0xc420051dc0)
command-line-arguments/_obj/_cgo_gotypes.go:60 +0x3a
command-line-arguments/_obj/_cgo_gotypes.go:60 +0x3a
main._cgoexpwrap_cfb3840e3af2_getGoPtr(0xc420016078)
command-line-arguments/_obj/_cgo_gotypes.go:62 +0x67
command-line-arguments/_obj/_cgo_gotypes.go:62 +0x67
main._Cfunc_Main()
command-line-arguments/_obj/_cgo_gotypes.go:43 +0x41
command-line-arguments/_obj/_cgo_gotypes.go:43 +0x41
main.main()
/Users/chai/go/src/github.com/chai2010/advanced-go-programming-book/examples/ch2-xx/return-go-ptr/main.go:17 +0x20
/Users/chai/go/src/github.com/chai2010 \
/advanced-go-programming-book/examples/ch2-xx \
/return-go-ptr/main.go:17 +0x20
exit status 2
```

Expand Down
2 changes: 1 addition & 1 deletion ch2-cgo/ch2-08-class.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ struct Int {
int Twice() {
const int* p = (int*)(this);
return (*p) * 2;
}
}
};
int main() {
int x = 42;
Expand Down
8 changes: 4 additions & 4 deletions ch3-asm/ch3-01-basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var Id = 9527
```
$ go tool compile -S pkg.go
"".Id SNOPTRDATA size=8
0x0000 37 25 00 00 00 00 00 00 '.......
0x0000 37 25 00 00 00 00 00 00 '.......
```

其中`go tool compile`命令用于调用Go语言提供的底层命令工具,其中`-S`参数表示输出汇编格式。输出的汇编比较简单,其中`"".Id`对应Id变量符号,变量的内存大小为8个字节。变量的初始化内容为`37 25 00 00 00 00 00 00`,对应十六进制格式的0x2537,对应十进制为9527。SNOPTRDATA是相关的标志,其中NOPTR表示数据中不包含指针数据。
Expand Down Expand Up @@ -117,10 +117,10 @@ var Name = "gopher"
```
$ go tool compile -S pkg.go
go.string."gopher" SRODATA dupok size=6
0x0000 67 6f 70 68 65 72 gopher
0x0000 67 6f 70 68 65 72 gopher
"".Name SDATA size=16
0x0000 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 ................
rel 0+8 t=1 go.string."gopher"+0
0x0000 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 ................
rel 0+8 t=1 go.string."gopher"+0
```

输出中出现了一个新的符号go.string."gopher",根据其长度和内容分析可以猜测是对应底层的"gopher"字符串数据。因为Go语言的字符串并不是值类型,Go字符串其实是一种只读的引用类型。如果多个代码中出现了相同的"gopher"只读字符串时,程序链接后可以引用的同一个符号go.string."gopher"。因此,该符号有一个SRODATA标志表示这个数据在只读内存段,dupok表示出现多个相同标识符的数据时只保留一个就可以了。
Expand Down
2 changes: 1 addition & 1 deletion ch3-asm/ch3-06-func-again.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ L_STEP_TO_END:
L_END:
MOVQ $0, result+8(FP) // return 0
RET
RET
```

在汇编版本函数中并没有定义局部变量,只有用于调用自身的临时栈空间。因为函数本身的参数和返回值有16个字节,因此栈帧的大小也为16字节。L_STEP_TO_END标号部分用于处理递归调用,是函数比较复杂的部分。L_END用于处理递归终结的部分。
Expand Down
Loading

0 comments on commit 9ad62fe

Please sign in to comment.