cloudnativebooks / cloud-native-go Goto Github PK
View Code? Open in Web Editor NEW华为云原生丛书之《Go专家编程》
华为云原生丛书之《Go专家编程》
问题描述
A clear and concise description of what the bug is.
如何找到这个错误
您认为应该如何?
缺少空格
-modulegithub.com/renhongcai/exclude
+module github.com/renhongcai/exclude
如何找到这个错误
您认为应该如何?
缺少空格
-GOSUMDB="<checksum database name>+<publickey><checksum service URL>"
+GOSUMDB="<checksum database name>+<public key> <checksum service URL>"
如何找到这个错误
您认为应该如何?
GOSUMDB树最底层的节点有时说成“树的根部”,容易引起误解,误以为最顶层的根节点。不如就按前文叫“底层节点”,或者叫“叶子节点”也可以。
如何找到这个错误
章节:12.3.11-2-6
页码:351
章节:12.3.13-3-1
页码:364-366
您认为应该如何?
有些地方包名用 go.dog
开头,例如go.dog/uuid
,这是有意为之吗?
如何找到这个错误
您认为应该如何?
缺少点号
- 1 Go 1.11
+1. Go 1.11
问题描述
当defer中再次引发panic,应该跳过该defer函数的执行,而不是尝试再次执行。
如何找到这个错误
您认为应该如何?
if d.started {
if d._panic != nil {
d._panic.aborted = true
}
d._panic = nil
+ d.fn = nil
+ gp._defer = d.link
+ freedefer(d)
+ continue
}
d.started = true
d._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
+d._panic = nil
d.fn = nil
gp._defer = d.link
以上逻辑参考了go源码src/runtime/panic.go:gopanic
其他补充信息
问题描述
触发扩容条件中的第2项:overflow的数量大于2^15,即overflow数量超过32768
看源码应该是overflow的数量大于等于 2^min(15,B)
func tooManyOverflowBuckets(noverflow uint16, B uint8) bool {
// If the threshold is too low, we do extraneous work.
// If the threshold is too high, maps that grow and shrink can hold on to lots of unused memory.
// "too many" means (approximately) as many overflow buckets as regular buckets.
// See incrnoverflow for more details.
if B > 15 {
B = 15
}
// The compiler doesn't see here that B < 16; mask B to generate shorter shift code.
return noverflow >= uint16(1)<<(B&15)
}
如何找到这个错误
您认为应该如何?
应该为:overflow的数量大于等于 2^min(15,B)
其他补充信息
问题描述
触发扩容条件中的第2项:overflow的数量大于2^15,即overflow数量超过32768
看源码应该是overflow的数量大于等于 2^min(15,B)
func tooManyOverflowBuckets(noverflow uint16, B uint8) bool {
// If the threshold is too low, we do extraneous work.
// If the threshold is too high, maps that grow and shrink can hold on to lots of unused memory.
// "too many" means (approximately) as many overflow buckets as regular buckets.
// See incrnoverflow for more details.
if B > 15 {
B = 15
}
// The compiler doesn't see here that B < 16; mask B to generate shorter shift code.
return noverflow >= uint16(1)<<(B&15)
}
如何找到这个错误
您认为应该如何?
应该为:overflow的数量大于等于 2^min(15,B)
其他补充信息
https://github.com/golang/go/blob/go1.16.12/src/runtime/map.go#L1074-L1087
问题描述
exam.go:88行 // 写nil管道不会阻塞
exam_test.go: 31行 // 写nil管道会阻塞,不能添加期望值
您认为应该如何?
两者之间是否有矛盾呢?读写nil管道都会阻塞吧
图片
如果有可能,尽量提供图片。
其他补充信息
-检测多行输出格式为// Output: \ <期望字符串> \ <期望字符串>
-检测无序输出格式为// Unordered output: \ <期望字符串> \ <期望字符串>
+检测多行输出格式为// Output: \n <期望字符串> \n <期望字符串>
+检测无序输出格式为// Unordered output: \n <期望字符串> \n <期望字符串>
-可通过参数timeout <n>指定
+可通过参数-timeout <n>指定
-性能测试:runExamples
-示例测试:runBenchmarks
+性能测试:runBenchmarks
+示例测试:runExamples
--count=N参数可以指定执行benchmarkN次
+-count=N参数可以指定执行benchmark N次
章节12.3.11-1,页码349:
本节末尾提到可以用,
分割多个proxy,在1.15中如果想在出错时继续尝试下一个proxy,还可以使用|
。感觉可以更新下?
问题描述
13.1节的内容感觉有点多余,因为13.3节已经解析到append时值传递所以不可能操作原来的slice,那13.1节分析的扩容感觉不是问题所在,即使不扩容,只要不接收返回返回值,原来的slice也是不会变化。
在用for...range迭代string时,range返回的第二个值是rune类型,其内容为对应字符的(完整的)Unicode码点。不过书中一直说是Unicode编码的首字节,而不是全部。
Go语言规范中的说法也是Unicode码点:https://golang.org/ref/spec#For_range
For a string value, the "range" clause iterates over the Unicode code points in the string starting at byte index 0. On successive iterations, the index value will be the index of the first byte of successive UTF-8-encoded code points in the string, and the second value, of type rune, will be the value of the corresponding code point.
书中涉及之处有:
range作用于string时……元素值是该字符对应的Unicode编码的首个字节的值
range的第二个返回值的类型为rune类型,它仅代表Unicode编码的1个字节
返回的元素值为rune类型的单个字节值……该字节值仅代表Unicode编码的首个字节
-循环变量各个case时,循环能正常结束
+循环遍历各个case时,循环能正常结束
题目四
-本题答案为D。
+本题答案为C。
-由于range可以给循环变量赋值,使其起来好像函数返回一样
+由于range可以给循环变量赋值,使其看起来好像函数返回一样
问题描述
go1.16.6
Add()操作必须早于Wait(),否则会触发panic
如何找到这个错误
您认为应该如何?
go1.16.6版本,Wait早于Add()现在也不会panic了
不知道是不是golang版本的因素
代码
func main() {
var wg sync.WaitGroup
wg.Wait() //Wait早于Add()现在也不会panic了
wg.Add(2) //设置计数器,数值即为goroutine的个数
go func() {
time.Sleep(1 * time.Second)
fmt.Println("Goroutine 1 finished!")
wg.Done() //goroutine执行结束后将计数器减1
}()
go func() {
time.Sleep(2 * time.Second)
fmt.Println("Goroutine 2 finished!")
wg.Done() //goroutine执行结束后将计数器减1
}()
wg.Wait() //主goroutine阻塞等待计数器变为0
fmt.Printf("All Goroutine finished!")
}
收集了一些可能可以改进的地方,但会过多关注于细节,也可能说的不对,所以本issue仅供参考。
协程读取管道时,阻塞的条件有:
-管道无缓冲区;
+管道无缓冲区,且不存在阻塞等待写入的协程;
协程写入管道时,阻塞的条件有:
-管道无缓冲区;
+管道无缓冲区,且不存在阻塞等待读取的协程;
与“sendq非空==N”的后续条件保持一致
-有缓冲区?
+qcount>0?
for-range迭代channel的伪代码,将变量名”index“改为”value“更合理。
-(3)从mcache的alloc[class]链表中查询可用的span。
+(3)从mcache的alloc[class*2]或alloc[class*2+1]链表中查询可用的span。
-Add()设置的值必须与实际等待的goroutine的个数一致,否则会触发panic。
+Add()设置的值必须与实际等待的goroutine的个数一致,否则会触发panic或导致死锁。
common.sub
-子测试列表
+并发运行的子测试列表
-任何实现了该方法的结构体都可以作为error来使用
+任何实现了该方法的数据类型都可以作为error来使用
-类型断言替换成errors.As()时需要先声明一个目标类型的指针变量
+类型断言替换成errors.As()时需要先声明一个目标类型的变量,再传入该变量的指针
示例中*os.PathError
实现了error接口,即os.PathError
的指针类型实现了error接口,因此声明了该类型的变量,再取该变量的指针(即指针的指针)传入errors.As()
。
-GOMAXPROCS的值不超过64的话,timersBucket桶的数量等于GOMAXPROCS。
+GOMAXPROCS的值不超过64的话,timersBucket桶的数量不会超过GOMAXPROCS。
如何找到这个错误
您认为应该如何?
-保证定时器的按照约定的时间触发
+保证定时器按照约定的时间触发
如何找到这个错误
您认为应该如何?
-sleeping...gp会投入睡眠
+sleeping...gp会进入睡眠
如何找到这个错误
您认为应该如何?
插图
timersBucket
-g
+gp
t
...
如何找到这个错误
您认为应该如何?
不太通顺,猜测可能的意思是
-timerproc实际上专门监控定时器的协程执行体
+timerproc实际是上专门监控定时器的协程
如何找到这个错误
您认为应该如何?
猜测可能的意思是
-从Go 1.14起,处理器不再由timerproc处理
+从Go 1.14起,定时器不再由timerproc处理
我个人觉得应该给出针对有缓冲区的管道、无缓冲区的管道的分开论述,毕竟无缓冲区的管道也可以进行 x, ok := <-ch。例如:
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
ch <- 1
}()
x, ok := <-ch
fmt.Printf("x=%v,ok=%v\n", x, ok) // x=1,ok=true
close(ch)
x, ok = <-ch
fmt.Printf("x=%v,ok=%v\n", x, ok) // x=0,ok=false
}
这样才可以避免读者,在看到这一节的最后的一句“可以看到,只有管道已关闭且缓冲区中没有数据时,管道读取表达式返回的第二个变量才与管道关闭状态一致”时,误以为只有 “有缓冲区的”管道才可以这样操作,或认为“状态一致”只能在“有缓冲区的”管道中才会存在等。
[edit]
因读阻塞的协程会被向管道写入数据的协程唤醒。
因写阻塞的协程会被从管道读数据的协程唤醒。
”
个人觉得可以多一个字“取”,或少一个字“入”,这样看起对仗工整一点。
改后的效果:
“
因读阻塞的协程会被向管道写入数据的协程唤醒。
因写阻塞的协程会被从管道读取数据的协程唤醒。
”
或
“
因读阻塞的协程会被向管道写数据的协程唤醒。
因写阻塞的协程会被从管道读数据的协程唤醒。
”
[edit]
入
字删除,因为写数据协程唤醒阻塞的协程时,实际上数据还没写入。已修改根据前后文,个人建议都使用 长度、容量。
[edit]:
capacity
和length
之处,上下文一般都有数据结构的描述,个人感觉使用英文单词更容易理解。如果我理解不对,还请指出具体修改点,感谢。多了一个“在”字,应该是”而Go语言的map则在负载因子达到6.5..."吧?
[edit]:
根据您在第46页中关于ValueSpec结构体的定义,这里的Name和Value应该修改成Names和Values吧?
若需要修改成Names和Values,则这两句可能需要修改成:
Names用于存储常量的名字,使用切片表示单行语句中声明的多个常量。
Values用于存储常量的值,与Names对应,表示常量的初始值。
[edit]:
diff --git a/chapter01/5.3-iota_principle.md b/chapter01/5.3-iota_principle.md
index c04b328..2de63d0 100644
--- a/chapter01/5.3-iota_principle.md
+++ b/chapter01/5.3-iota_principle.md
@@ -29,9 +29,9 @@ const (
上面的常量声明块中仅包括一行声明语句,该语句对应一个`ValueSpec`结构。
- Doc 表示块注释,往往会出现在文档中的注释;
-- Name 表示常量的名字,使用切片表示单行语句中声明的多个常量;
-- Type 常量类型;
-- Value 常量值,与Name对应,表示常量的初始值;
+- Names 表示常量的名字,使用切片表示单行语句中声明的多个常量;
+- Type 表示常量类型;
+- Values 表示常量值,与Name对应,表示常量的初始值;
- Comment 表示行注释
少了一个“常”字,应该是“Type为常量类型”吧?
[edit]:
这里的“字节值”,需要修改成“字符值”。
[edit]:
diff --git a/chapter01/6.2-string_usecase.md b/chapter01/6.2-string_usecase.md
index 7bd4422..5b9316a 100644
--- a/chapter01/6.2-string_usecase.md
+++ b/chapter01/6.2-string_usecase.md
@@ -88,7 +88,7 @@ func StringToByte() {
#### 2.1 UTF编码
string使用8比特字节的集合来存储字符,而且存储的是字符的UTF-8编码,例如每个汉字字符的UTF-8编码将占用多个字节。
-在使用for-range遍历字符串时,每次迭代将返回字符UTF-8编码的首个字节下标及字节值,这意味着下标可能不连续。
+在使用for-range遍历字符串时,每次迭代将返回字符的UTF-8编码首个字节下标及字符值,这意味着下标可能不连续。^M
比如下面的函数:
我想您要表达的是:对一个字符串的元素进行取地址操作。(ps: 这里的元素一说,我是看了go语言规范String types一节中的“It is illegal to take the address of such an element; if s[i] is the i'th byte of a string, &s[i] is invalid.”)。所以我觉得这里是有一点问题。字符串是可以进行取地址操作,例如:
package main
import "fmt"
func main() {
s := "你好世界!你好**"
fmt.Printf("%p\n", &s)
s1 := s[0]
fmt.Printf("%p\n", &s1)
// fmt.Printf("%p\n", &s[0]) // 编译报错:invalid operation: cannot take address of s[0] (value of type byte)
}
[edit]:
diff --git a/chapter01/6.2-string_usecase.md b/chapter01/6.2-string_usecase.md
index 5b9316a..d090b06 100644
--- a/chapter01/6.2-string_usecase.md
+++ b/chapter01/6.2-string_usecase.md
@@ -115,7 +115,7 @@ s := "Hello"
&s[0] = byte(104) // 非法
s = "hello" // 合法
-字符串不支持取地址操作,也就无法修改字符串值,上面的语句中会有编译错误:
+字符串元素不支持取地址操作,也就无法修改字符串值,上面的语句中会有编译错误:
这里多了一个“示”字。
[edit]:
这里我想不用在string(b)的前后加上双引号。
[edit]:
选项C看起来也是对的。若是对的,则题目三应该是一个多选题。
[edit]:
其中的“它不同”应该是“它不能”吧?
[edit]:
这句看起好像少了一个“能”,但多一个“能”字看起来有点奇怪,我觉得可以把“够”字换成“可”字。
[edit]:
特定场景下可提升性能
根据您前文的描述,这里的“多个case语句中”,我觉得,应该要修改成“全部case语句中”,多个的意思是大于1个,但并不表示全部的意思。例如:
package main
import "fmt"
func SelectForChan(c1 chan int, c2 chan int, c3 chan int) {
select {
case d := <-c1:
fmt.Printf("c1 received: %d\n", d)
case c1 <- 1:
fmt.Printf("c1 sent %d\n", 1)
case d := <-c2:
fmt.Printf("c2 received: %d\n", d)
case c2 <- 2:
fmt.Printf("c2 sent %d\n", 2)
case d := <-c3:
fmt.Printf("c3 received: %d\n", d)
case c3 <- 3:
fmt.Printf("c3 sent %d\n", 3)
}
}
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int, 1)
SelectForChan(ch1, ch2, ch3)
}
[edit]:
您在第86页给出的答案是D(函数触发panic),但根据您第86页的描述似乎答案应该是C(函数打印hi后阻塞)
但这道题,我觉得,可能还跟怎么调用该函数有关。例如:
package main
import (
"fmt"
"time"
)
func RangeTimer() {
defer func() {
if r := recover(); r != nil {
fmt.Println("panic: ", r)
}
}()
t := time.NewTimer(time.Second)
for _ = range t.C {
fmt.Println("hi")
}
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("panic: ", r)
}
}()
go RangeTimer()
time.Sleep(20 * time.Second)
}
将会打印出“hi”, 同时没有发生panic
如果是以下方式调用(少了 在 RangeTimer 前面使用 go关键字):
package main
import (
"fmt"
"time"
)
func RangeTimer() {
defer func() {
if r := recover(); r != nil {
fmt.Println("panic: ", r)
}
}()
t := time.NewTimer(time.Second)
for _ = range t.C {
fmt.Println("hi")
}
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("panic: ", r)
}
}()
RangeTimer()
time.Sleep(20 * time.Second)
}
则会打印出“hi”,之后报错:fatal error: all goroutines are asleep - deadlock!
所以这里我也不知道最后的答案是哪一个了。
[edit]:
“使其起来好像”应该是少了一个“看”字,应该是“使其看起来好像”吧?
[edit]:
这里的表述好像有点问题,我看其他文章或博客,说rune表示的是一个Unicode码点或字符。
[edit]:
这里malloc()在C语言中应该是函数,面向对象的编程语言或类似面向对象的编程语言中才有“方法”,所以这里应该是需要将“方法“这两字修改成“函数”吧?
[edit]:
这里“列锁”,应该需要修改成“死锁”吧?
[edit]:
少了一个字母“n”,应该是content.Background
[edit]:
emptCtx少了一个字母“y”,应该是emptyCtx吧?
[edit]:
其中的backgroud,应该都是少了一个字母“n”,应该是background吧?
[edit]:
这里的“继承于”,与您在第36页提到的“Go语言的struct与其他编程语言的class有些类似可以定义字段和方法,但是不可以继承。”,有一些矛盾。我看了官方的的 FAQ-Why is there no type inheritance?,以及 FAQ-Why doesn't Go have "implements" declarations?,说法和您在第36页说的一致。所以我想第133页的“继承于”应该修改成“实现了”吧?
[edit]:
我看了go1.11源码中的WithCancel:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() { c.cancel(true, Canceled) }
}
go 1.20.6的源码中的WithCancel:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
c := withCancel(parent)
return c, func() { c.cancel(true, Canceled, nil) }
}
感觉这句话好像有点问题,我个人觉得可以修改成:“实际上,WithCancel()返回的第二个值的匿名函数中用于cancel context的方法正是此cancel()。”
[edit]:
若134页改成使用到“匿名函数”,似乎这里就需要修改成“返回cancelCtx实例和cancel匿名函数。”
“最后返回interface{}”,我看了go1.20.6的源码,其返回的是nil。不知道这里的interface{},是不是应该写成nil?
[edit]:
我看了您在97页中标注的是“P(processor):处理器...”,而这里写的是“Process”,我想应该是“Processor”吧?
[edit]:
我个人感觉,这两句话读起来有点奇怪的感觉(句子表达中含有集合的概念)。我觉得可以修改成:
“题目一:如何判断两个Foo结构体变量是否相等?...” 和 “题目二:如何判断两个空接口类型变量是否相等?”
[edit]:
这句的后面部分“go test只会执行以此开头的方法”表述有点不对,和您在171页中的写到的“执行测试可以使用go test,此时该目录下的其他测试文件也会一并执行。”有点矛盾了。
还有一点,就是这句以“测试函数”开始、以“方法”结束,好像说的都是同一个事物,是否应该统一一下说法。
可以直接去除掉“只会”中的“只”,将方法修改为“测试函数”,修改后的效果:
“测试函数命名规则为TestXxx,其中Test为单元测试的固定开头,go test会执行以此开头的测试函数。”
[edit]:
应该需要修改为“//MakeSliceWithoutAlloc,不预分配内存”吧?
[edit]:
目前我只在Windows系统上进行测试,OutPut中的P大写,是不影响示例测试的,但不知道在Linux中的是否会出现问题。
根据pkg testing 的说明给出的是:"Output: " 和 "Unordered output:"。
[edit]:
Output
。从 Go 1.16 开始,go install 是推荐用于构建和安装程序的命令。
-d 标志告诉 go get 不要构建或安装包。当使用 -d 时,go get 将只管理 go.mod 中的依赖项。
在没有-d的情况下使用go get来构建和安装包已经被废弃了(从Go 1.17开始)。
在 Go 1.18 中,-d 将永远被启用。
所以这里建议标注下不同版本的安装方式。go 1.16 是2021年2月16日发布的。
对于大于等于 go 1.16,应该建议使用以下方式安装:
go install golang.org/x/pref/cmd/benchstat@latest
[edit]:
pref
应该为 per
f。这里直接修改为 install
了。不想维护老版本的用法了,随时间推移,旧版本没必要再记了。这道题根据您下面的描述,应该也是为了说“答案为B和C”的!
以下运行后的结果
package main
import (
"errors"
"fmt"
)
func main() {
err := errors.New("not found")
err1 := fmt.Errorf("some context: %v", err)
err2 := fmt.Errorf("some context: %w", err)
fmt.Printf("err1的类型:%T\n", err1)
fmt.Printf("err1的类型:%T\n", err2)
fmt.Println(err1.Error())
fmt.Println(err2.Error())
if err1.Error() == err2.Error() {
fmt.Println("eq")
} else {
fmt.Println("neq")
}
}
// Output:
//err1的类型:*errors.errorString
//err1的类型:*fmt.wrapError
//some context: not found
//some context: not found
//eq
所以这道选择题最终的答案应该是“B和C”吧?
[edit]:
是否应该在panic后加一个“后”字,应该是“触发panic后函数中的defer语句是否会执行”吧?
[edit]:
应该是少了在 ticker := time.NewTicker(5 * time.Minute)
之后一行加上 defer ticker.Stop()
吧?
[edit]:
这里,我猜测,是需要在“但并”后面加上一个“不”字,应该是“然而,虽然应用很广泛,但并不代表大家对它有深刻的认识”
[edit]:
虽然有些博客,或文章,弱化了形参和实参的称法,但我个人觉得还是有必要区分下。故这里我觉得应该是“大多数情况下,Go编译器根据传递的实参可以自动推导出类型”吧?
[edit]:
多了一个加粗显示的"module",以及少了在import 后面的一对双引号,应该是“例如,要引用 module github.com/rehongcai/indirect中的内容时,其import路径需要为import "github.com/renhongcai/indirect" ” 吧?
[edit]:
根据您在345页的表述,这里应该还少了345页描述中的第二种情况吧?所以我在想是不是可以在“只在依赖包版本不包含”后加上“在其”两个字,完整的表述是“go.mod只需记录直接依赖的依赖包版本,只在依赖包版本不包含在其go.mod文件时才会记录间接依赖包版本,...” ?
[edit]:
目前,我只读到 358页 ,后续阅读遇到问题再来请教下您。
不好意思,没按照您要求的格式给您的第二版书提出勘误,望见谅!
-切取的长度为 hight - low
+切取的长度为 high - low
-如果当前map处理搬迁过程中
+如果当前map处于搬迁过程中
-string转[]byte
-func StringToByte() {
+[]byte转string
+func ByteToString() {
...
}
-[]byte转string
-func ByteToString() {
+string转[]byte
+func StringToByte() {
...
}
问题描述
执行结果是false
如何找到这个错误
您认为应该如何?
package main
import "fmt"
func SliceExtend() {
var slice []int
s1 := append(slice, 1, 2, 3)
s2 := append(s1, 4)
fmt.Println(&s1[0] == &s2[0])
fmt.Println(&s1[0], &s2[0])
}
func main() {
SliceExtend()
}
结果应该是false
问题描述
go test example_test.go 执行报错:
.\example_test.go:12:2: undefined: SayHello
.\example_test.go:17:2: undefined: SayGoodbye
.\example_test.go:24:2: undefined: PrintNames
FAIL command-line-arguments [build failed]
如何找到这个错误
您认为应该如何?
应该改成:
go test example_test.go example.go
图片
如果有可能,尽量提供图片。
其他补充信息
编译优化小节说临时将[]byte转为string的场景,编译器会优化为直接把string.str指向[]byte的底层数据,避免复制。这样会不会引起并发问题,如果有另一个协程正在操作这个[]byte会有问题吗?
插图中的bitmap
-512GB
+16GB
-会将span中的一页会划分为更小的粒度
+会将span中的一页划分为更小的粒度
-即 (bytes/spans) / (bytes/obj)
+即 (bytes/span) / (bytes/obj)
-即 (bytes/spans) % (bytes/obj)
+即 (bytes/span) % (bytes/obj)
插图中的spans
-521MB
+512MB
除了常规的按现有容量×2或×1.25倍,有个特殊情况是如果append新加入的元素超过了按倍数扩容的容量,其实际扩容容量会满足append的需求,经过测试貌似是实际需求容量向上取偶数,测试代码如下:
s:=[]int{1,2,3,4,5,6,7,8}
fmt.Println(len(s),cap(s)) // 8 8
s1:=append(s,9,10,11,12,13,14,15,16)
fmt.Println(len(s1),cap(s1)) // 16 16
s2:=append(s,9,10,11,12,13,14,15,16,17)
fmt.Println(len(s2),cap(s2)) // 17 18
s3:=append(s,9,10,11,12,13,14,15,16,17,18)
fmt.Println(len(s3),cap(s3)) // 18 18
s4:=append(s,9,10,11,12,13,14,15,16,17,18,19)
fmt.Println(len(s4),cap(s4)) // 19 20
s5:=append(s,9,10,11,12,13,14,15,16,17,18,19,20)
fmt.Println(len(s5),cap(s5)) // 20 20
s6:=append(s,9,10,11,12,13,14,16,16,17,18,19,20,21)
fmt.Println(len(s6),cap(s6)) // 21 22
s7:=append(s,9,10,11,12,13,14,17,17,17,18,19,20,21,22)
fmt.Println(len(s7),cap(s7)) // 22 22
问题描述
// 题目二: 引用循环变量下标
func PrintSlice() {
s := []int{1, 2, 3}
var wg sync.WaitGroup
wg.Add(len(s))
for _, v := range s {
go func() {
fmt.Println(v)
wg.Done()
}()
}
wg.Wait()
}
// Output并不是 3, 3, 3,三个协程会从数组中随机执行
如何找到这个错误
您认为应该如何?
=== RUN TestPrintSlice
3
2
1
--- PASS: TestPrintSlice (0.00s)
图片
如果有可能,尽量提供图片。
其他补充信息
问题描述
2.2.1,77页
题目四,“答案为D ” 。这个是错的。应该为:“ 答案为C”
如何找到这个错误
您认为应该如何?
图片
如果有可能,尽量提供图片。
其他补充信息
我写了代码进行测试:
package main
import (
"fmt"
"time"
)
func main() {
RangeTimer()
}
func RangeTimer() {
t := time.NewTimer(time.Second)
for _ = range t.C {
fmt.Println("hi")
}
}
输出:
hi
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.RangeTimer()
/Users//go/src/gitee.com/wide288/test/for-range1/main.go:15 +0xcc
main.main()
/Users//go/src/gitee.com/wide288/test/for-range1/main.go:9 +0x25
mspan
中被引用的对象后产生的gcmarkBits
,会作为新的allocBits
,那么是否也应该同时更新allocCount
?gcmarkBits
是在mspan中,Go是如何通过对象地址反向找出对应mspan
的?之前读到context的定义,其中嵌入了上级类型,例如cancelCtx
中的Context
type cancelCtx struct {
Context
......
}
我一直以为仅仅是重用了上一级的接口定义,与parent之间的联系由私有成员变量维护,而实际是直接在嵌入类型中存放了parent实例,之前一直没留意到,书中也没重点提及,感觉可以加强一下。
问题描述
习题五
对下面的函数描述正确的是(单选)
func SelectExam5() {
select {}
}
答案是:C函数陷入阻塞
但是实际的执行结果是:A:编译错误,select语句非法
如何找到这个错误
您认为应该如何?
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
main.main()
应该是 A:编译错误,select语句非法
-协程调度器……及时把阻塞的协程调度出协程
+协程调度器……及时把阻塞的协程调度出线程
猜测可能是这个意思?
章节12.3.11-1,页码349:
本节末尾提到可以用,
分割多个proxy,在1.15中如果想在出错时继续尝试下一个proxy,还可以使用|
。感觉可以更新下?
https://golang.org/doc/go1.15#go-command
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.