ffhelicopter / go42 Goto Github PK
View Code? Open in Web Editor NEW《Go语言四十二章经》详细讲述Go语言规范与语法细节及开发中常见的误区,通过研读标准库等经典代码设计模式,启发读者深刻理解Go语言的核心思维,进入Go语言开发的更高阶段。
《Go语言四十二章经》详细讲述Go语言规范与语法细节及开发中常见的误区,通过研读标准库等经典代码设计模式,启发读者深刻理解Go语言的核心思维,进入Go语言开发的更高阶段。
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!")
}
复数使用 re+imI 来表示,其中 re 代表实数部分,im 代表虚数部分,I 代表根号负 1
I是小写的
格式化这块有些小问题
结果介绍里面是下面这种输出。这里应该是格式化字符串用错了,不是合理的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)
应该这样:
//LoadOrStore
//若key不存在,则存入key和value,返回false和输入的value
v, ok := m.LoadOrStore("name1", "Jim")
fmt.Println(ok, v) //false Jim
//若key已存在,则返回true和key对应的value,不会修改原来的value
v, ok = m.LoadOrStore("name", "aaa")
fmt.Println(ok, v) //true Joe
国内可用goproxy解决网络问题,见https://goproxy.cn
如果defer的代码块放在了函数退出代码的后面,那么defer中的代码块也是是无法执行到的
佩服
Thanks a lot.
第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
Great work! have you ever considered to put this on gitbook?
首先感谢输出的文章,README中有一个 typo,虽然不影响理解,修改一下应该更好。
- 第一章到第二十六章
+ 第一章到第十六章 +
可能有吹毛求疵的嫌疑:smile:
15.2 Panic 的案例 ParseError 是什么?
...
if err != nil {
panic(&ParseError{idx, field, err})
}
...
在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不是空字符串又不一样。
原版:
程序输出:
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么?
参考源码,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
?
好像没看到明确的开源协议,注明出处是否可以转载呢
x 被定义为:var x float64 = 3.4,那么 reflect.TypeOf(x) 返回 float64,reflect.ValueOf(x) 返回 。
漏了reflect.ValueOf(x) 返回值
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)
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
但是对于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)))。
type ReaderWriter struct {
*io.Reader
*io.Writer
}
接口是不能用指针的
func main() {
map2 := make(map[[2]int]interface{})
array := [2]int{1,2}
map2[array] = 1
fmt.Println(map2)
}
可以正常输出
本小节最后的示例代码如下:
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。
下面代码通过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)。
%f: 多个冒号,应该%f
https://github.com/ffhelicopter/Go42/blob/master/content/42_07_package.md
如果为main包,运行Go buil则会在GOPATH/bin 生成一个可执行的二进制文件。
build 少了一个 d
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.