Code Monkey home page Code Monkey logo

go42's Introduction

travis Go Report Card

作者:ffhelicopter(李骁) 完稿时间:2018-04-15

进阶阅读

《Go语言四十二章经》开源电子书升级版《深入学习Go语言》,在当当,天猫,京东有售,感谢各位对此书的支持与关注!

本书适合初次学习Go语言,以及对Go语言有初步了解的开发者,读者可通过本书努力在尽量短的时间内成长为一名合格的Go语言开发者。

go.png

前言

写《Go语言四十二章经》,纯粹是因为开发过程中碰到过的一些问题,踩到过的一些坑,感觉在Go语言学习使用过程中,有必要深刻理解这门语言的核心思维、清晰掌握语言的细节规范以及反复琢磨标准包代码设计模式,于是才有了这本书。

Go语言以语法简单、门槛低、上手快著称。但入门后很多人发现要写出地道的、遵循 Go语言思维的代码却是不易。

在刚开始学习中,我带着比较强的面向对象编程思维惯性来写代码。但后来发现,带着面向对象的思路来写Go 语言代码会很难继续写下去,或者说看了系统源代码或其他知名开源包源代码后,围绕着struct和interface来写代码会更高效,代码更美观。虽然有人认为,Go语言的strcut 和 interface 一起,配合方法,也可以理解为面向对象,这点我姑且认可,但开发中不要过意考虑这些。因为在Go 语言中,interface接口的使用将更为灵活,刻意追求面向对象,会导致你很难理解接口在Go 语言中的妙处。

作为Go语言的爱好者,在阅读系统源代码或其他知名开源包源代码时,发现大牛对这门语言的了解之深入,代码实现之巧妙优美,所以我建议你有时间多多阅读这些代码。网上有说Go大神的标准是“能理解简洁和可组合性哲学”,的确Go语言追求代码简洁到极致,而组合**可谓借助于struct和interface两者而成为Go的灵魂。

function,method,interface,type等词语是程序员们接触比较多的关键字,但在Go语言中,你会发现,其有了更强大,更灵活的用法。当你彻底理解了Go语言相关基本概念,以及对其特点有深入的认知,当然这也这本书的目的,再假以时日多练习和实践,我相信你应该很快就能彻底掌握这门语言,成为一名出色的Gopher。

这本书适合Go语言新手来细细阅读,对于有一定经验的开发人员,也可以根据自己的情况,选择一些章节来看。

第一章到第二十六章主要讲Go语言的基础知识,其中第十七章的type,第十八章的struct,第十九章的interface,以及第二十章的方法,都是Go语言中非常非常重要的部分。

而第二十一章的协程,第二十二章的通道以及第二十三章的同步与锁,这三章在并发处理中我们通常都需要用到,需要弄清楚他们的概念和彼此间联系。

从第二十七章开始,到第三十八章,讲述了Go标准包中比较重要的几个包,可以仔细看源代码来学习大师们的编程风格。

从第三十九章开始到结尾,主要讲述了比较常用的第三方包,但由于篇幅有限,也就不展开来讲述,有兴趣的朋友可直接到相关开源项目详细了解。

最后,希望更多的人了解和使用Go语言,也希望阅读本书的朋友们多多交流。

祝各位Gopher们工作开心,愉快编码!

本书内容在github更新:https://github.com/ffhelicopter/Go42/blob/master/SUMMARY.md

go42's People

Contributors

12ain avatar 3lackrush avatar albertchamberlain avatar eval-exec avatar ffhelicopter avatar fuzhy avatar henng avatar sidbusy avatar weavingtan avatar xianyunyh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go42's Issues

Go slice 不是指针,而是包含指针的结构体

第12章,slice的介绍基本是错的。

绝对不要用指针指向 slice,切片本身已经是一个引用类型,所以它本身就是一个指针!

package main

import "fmt"

func main() {
	x := []int{0, 0, 0}
	test(x)
	fmt.Println(x)
}

func test(i []int) {
	i = []int{1, 2, 3}
}

输出 [0 0 0],如果按照作者的理论 slice 是指针的话,结果应该是 [1 2 3]

错太多了,建议作者再读读 https://blog.golang.org/go-slices-usage-and-internals

string转[]byte的陷阱

在string转[]byte中,有个非常典型的例子。有同学可以解释下为什么吗?
package main
import "fmt"
func main() {
s := []byte("")
s1 := append(s, 'a')
s2 := append(s, 'b')
//fmt.Println(s1, "==========", s2)
fmt.Println(string(s1), "==========", string(s2))
}
// 注释时候输出是 b ========== b
// 取消注释输出是 [97] ========== [98] a ========== b
// 如果s不是空字符串又不一样。

defer可以再补充点

如果defer的代码块放在了函数退出代码的后面,那么defer中的代码块也是是无法执行到的

27.1 反射(reflect)

x 被定义为:var x float64 = 3.4,那么 reflect.TypeOf(x) 返回 float64,reflect.ValueOf(x) 返回 。
漏了reflect.ValueOf(x) 返回值

README.md typo

首先感谢输出的文章,README中有一个 typo,虽然不影响理解,修改一下应该更好。

- 第一章到第二十六章
+ 第一章到第十六章 +

可能有吹毛求疵的嫌疑:smile:

23.1 同步锁示例中G1解锁后,G2和G3中一个加锁后另一个需要等待锁释放后才能加锁

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	wg := sync.WaitGroup{}

	var mutex sync.Mutex
	fmt.Println("Locking  (G0)")
	mutex.Lock()
	fmt.Println("locked (G0)")
	wg.Add(3)

	for i := 1; i < 4; i++ {
		go func(i int) {
			fmt.Printf("Locking (G%d)\n", i)
			mutex.Lock()
			fmt.Printf("locked (G%d)\n", i)

			time.Sleep(time.Second * 2)
			mutex.Unlock()
			fmt.Printf("unlocked (G%d)\n", i)
			wg.Done()
		}(i)
	}

	time.Sleep(time.Second * 5)
	fmt.Println("ready unlock (G0)")
	mutex.Unlock()
	fmt.Println("unlocked (G0)")

	wg.Wait()
}

程序输出:
Locking (G0)
locked (G0)
Locking (G1)
Locking (G3)
Locking (G2)
ready unlock (G0)
unlocked (G0)
locked (G1)
unlocked (G1)
locked (G3)
unlocked (G3)
locked (G2)
unlocked (G2)

关于28.2 指针运算代码示例的错误

但是对于v.j来说,怎么来得到它在内存中的地址呢?其实我们可以获取它相对于v的偏移量(unsafe.Sizeof可以为我们做这个事),但上面的代码并没有这样去实现。各位别急,一步步来。
var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uintptr(unsafe.Sizeof(int64(0)))))
其实我们已经知道v是有两个成员的,包括i和j,并且在定义中,i位于j的前面,而i是int32类型,也就是说i占4个字节。所以j是相对于v偏移了4个字节。您可以用uintptr(4)或uintptr(unsafe.Sizeof(int64(0)))来做这个事。unsafe.Sizeof方法用来得到一个值应该占用多少个字节空间。注意这里跟C的用法不一样,C是直接传入类型,而Go 语言是传入值。

以上这一段表述中将uintptr(4)等同于uintptr(unsafe.Sizeof(int64(0))),但其实uintptr(unsafe.Sizeof(int64(0)))==uintptr(8),但是这里var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uintptr(unsafe.Sizeof(int64(0)))))是可以正确取到j的值,是因为这里发生了对齐,除了i本身占用4字节,还有4个字节由编译器进行填充,导致unsafe.Offsetof(v.j)和uintptr(unsafe.Sizeof(int64(0)))在64位机器上,值都是8。原文说j是相对于v偏移了4个字节,实际上是错误的,而且也没有说清楚为什么使用uintptr(unsafe.Sizeof(int64(0)))。

第二十三章 同步与锁 程序输出是否有误?

原版:

程序输出:
Locking  (G0)
locked (G0)
Locking (G1)
Locking (G3)
Locking (G2)
ready unlock (G0)
unlocked (G0)
locked (G1)
unlocked (G1)
locked (G3)
locked (G2)
unlocked (G3)
unlocked (G2)

输出不应该是locked g3,unlock g3,再去locked g2么?

关于31.4 bufio包代码示例的错误

本小节最后的示例代码如下:

package main

import (
    "bufio"
    "fmt"
    "strings"
)

func main() {
    sr := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
    buf := bufio.NewReaderSize(sr, 0) //默认16
    b := make([]byte, 10)

    fmt.Println("==", buf.Buffered()) // 0
    S, _ := buf.Peek(5)
    fmt.Printf("%d ==  %q\n", buf.Buffered(), s) // 
    nn, er := buf.Discard(3)
    fmt.Println(nn, er)

    for n, err := 0, error(nil); err == nil; {
        fmt.Printf("Buffered:%d ==Size:%d== n:%d==  b[:n] %q ==  err:%v\n", buf.Buffered(), buf.Size(), n, b[:n], err)
        n, err = buf.Read(b)
        fmt.Printf("Buffered:%d ==Size:%d== n:%d==  b[:n] %q ==  err: %v == s: %s\n", buf.Buffered(), buf.Size(), n, b[:n], err, s)
    }

    fmt.Printf("%d ==  %q\n", buf.Buffered(), s)
}

其中第16行S应该为s。

模板章节的疑问

格式化这块有些小问题

结果介绍里面是下面这种输出。这里应该是格式化字符串用错了,不是合理的example.

const templ = ` 
{{range .}}----------------------------------------
Name:   {{.Name}}
Price:  {{.Price | printf "%4s"}} // 这块的模板函数不合理
{{end}}`
程序输出:
----------------------------------------
Name:   《三国演义》
Price:  %!s(float64=19.82)
----------------------------------------
Name:   《儒林外史》
Price:  %!s(float64=99.09)
----------------------------------------
Name:   《史记》
Price:  %!s(float64=26.89)

关于23.1 同步锁代码示例的错误

下面代码通过3个goroutine来体现sync.Mutex 对资源的访问控制特征:


package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    wg := sync.WaitGroup{}

    var mutex sync.Mutex
    fmt.Println("Locking  (G0)")
    mutex.Lock()
    fmt.Println("locked (G0)")
    wg.Add(3)

    for i := 1; i < 4; i++ {
        go func(i int) {
            fmt.Printf("Locking (G%d)\n", i)
            mutex.Lock()
            fmt.Printf("locked (G%d)\n", i)

            time.Sleep(time.Second * 2)
            mutex.Unlock()
            fmt.Printf("unlocked (G%d)\n", i)
            wg.Done()
        }(i)
    }

    time.Sleep(time.Second * 5)
    fmt.Println("ready unlock (G0)")
    mutex.Unlock()
    fmt.Println("unlocked (G0)")

    wg.Wait()
}
程序输出:
Locking  (G0)
locked (G0)
Locking (G1)
Locking (G3)
Locking (G2)
ready unlock (G0)
unlocked (G0)
locked (G1)
unlocked (G1)
locked (G3)
locked (G2)
unlocked (G3)
unlocked (G2)

这里的程序输出应该是不对的,在unlocked (G3)输出之前,G2还没有取到锁,不可能输出locked (G2)。

2.3 复数

复数使用 re+imI 来表示,其中 re 代表实数部分,im 代表虚数部分,I 代表根号负 1
I是小写的

第十章关于strings.Join和strings.Builder效率比较的问题

参考源码,Join本身就是调用了套了一个Builder来存新字符串,所以这两个效率应该是一样的?
go1.15.2 darwin/amd6

func Join(elems []string, sep string) string {
	switch len(elems) {
	case 0:
		return ""
	case 1:
		return elems[0]
	}
	n := len(sep) * (len(elems) - 1)
	for i := 0; i < len(elems); i++ {
		n += len(elems[i])
	}

	var b Builder
	b.Grow(n)
	b.WriteString(elems[0])
	for _, s := range elems[1:] {
		b.WriteString(sep)
		b.WriteString(s)
	}
	return b.String()
}

另外似乎strings.Builder是个改写版的迷你bytes.Buffer

35.2节错误未处理

35.2节方法err未处理
func tHandler(w http.ResponseWriter, r *http.Request) {
t, err := template.ParseFiles("layout.html.tmpl", "index.html.tmpl")
t.ExecuteTemplate(w, "layout", "Hello World!")
}

article title and sequence

could you rename the title as
42_1_xxx => 42_01_xxx
42_2_xxx => 42_02_xxx
then the article's sequence looks would be more nice

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.