从compare_4.go初识go的typecheck
主要是上一次的题目的第四道
上次compare
梳理了 go build
在compile
之前的准备工作,比如收集import
依赖关系
针对compare_4.go
进行编译,看一下一点compile
的过程,参数build -x -o ./compare_4 compare_4.go
package main
import "fmt"
func main() {
a := []byte("helloworld")
b := []byte("helloworld")
if a == b {
fmt.Printf("equal\n")
} else {
fmt.Printf("not equal\n")
}
}
可以看到终端输出:
WORK=/tmp/go-build082348361
mkdir -p $WORK/b001/
cat >$WORK/b001/_gomod_.go << 'EOF' # internal
package main
import _ "unsafe"
//go:linkname __debug_modinfo__ runtime/debug.modinfo
var __debug_modinfo__ = "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tcommand-line-arguments\nmod\tcommand-line-arguments\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"
var keepalive_modinfo = __debug_modinfo__
func init() { keepalive_modinfo = __debug_modinfo__ }
EOF
cat >$WORK/b001/importcfg << 'EOF' # internal
# import config
packagefile fmt=/usr/local/go/pkg/linux_amd64/fmt.a
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a
EOF
cd /media/chainhelen/LENOVO/xlworkspace/code/go/src/sh
/usr/local/go/pkg/tool/linux_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001 -p main -complete -buildid ii314DFgycKna9StCilp/ii314DFgycKna9StCilp -goversion go1.12.5 -D _/media/chainhelen/LENOVO/xlworkspace/code/go/src/sh -importcfg $WORK/b001/importcfg -pack -c=4 ./compare_4.go $WORK/b001/_gomod_.go
(我是在goland里面下了 `/usr/local/go/src/cmd/go` 断点,所以这个时候并没有删除临时WORK目录,断点位置在/usr/local/go/src/cmd/go/internal/work/gc.go:142)
可知在收集完信息之后,直接调用compile
工具(子进程),那么手动模拟一下编译过程
1. mkdir /tmp/test_self
2. 进入test_self目录,新建_gomod_.go,内容如下
package main
import _ "unsafe"
//go:linkname __debug_modinfo__ runtime/debug.modinfo
var __debug_modinfo__ = "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tcommand-line-arguments\nmod\tcommand-line-arguments\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"
var keepalive_modinfo = __debug_modinfo__
func init() { keepalive_modinfo = __debug_modinfo__ }
3.新建importcfg
# import config
packagefile fmt=/usr/local/go/pkg/linux_amd64/fmt.a
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a
4. 进入compare_4.go代码目录
/usr/local/go/pkg/tool/linux_amd64/compile -o /tmp/test_self/_pkg_.a -importcfg /tmp/test_self/importcfg ./compare_4.go /tmp/test_self/_gomod_.go
找一下对应的compile
代码
/usr/local/go/src/cmd/compile/internal/gc/typecheck.go:773
if !okfor[op][et] {
yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
n.Type = nil
return n
}
// okfor allows any array == array, map == map, func == func.
// restrict to slice/map/func == nil and nil == slice/map/func.
if l.Type.IsArray() && !IsComparable(l.Type) {
yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type)
n.Type = nil
return n
}
if l.Type.IsSlice() && !l.isNil() && !r.isNil() {
yyerror("invalid operation: %v (slice can only be compared to nil)", n)
n.Type = nil
return n
}
if l.Type.IsMap() && !l.isNil() && !r.isNil() {
yyerror("invalid operation: %v (map can only be compared to nil)", n)
n.Type = nil
return n
}
if l.Type.Etype == TFUNC && !l.isNil() && !r.isNil() {
yyerror("invalid operation: %v (func can only be compared to nil)", n)
n.Type = nil
return n
}
if l.Type.IsStruct() {
if f := IncomparableField(l.Type); f != nil {
yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
n.Type = nil
return n
}
}
相同类型中,map
、slice
、func
是不可以与自身类型比较的
对于array
比较性来说,其元素不可以拥有map、slice、func
等不可比较性的属性,否则也是不可以比较的;这种属性是在IsComparable
里面递归检查的