go常见问题与处理

1、出现错误内容reflect.Value.Set using unaddressable value?

一般出现 using unaddressable value 错误,表示传递的指针值不对,比如需要传递指针地址的,但是传了值,此时可以查看下gorm的语句中Find()中的值是否传递的是指针,如果不是指针就会报错

2、go build的执行流程是什么?

通过go build -n 执行代码(只打印过程,不真正执行),我们查看下go build的执行过程,如下:

[root@VM-12-12-centos gong]# go build -n abc.go 

#
# command-line-arguments
#

mkdir -p $WORK/b001/
cat >$WORK/b001/importcfg << 'EOF' # internal
# import config
packagefile fmt=/usr/local/go/pkg/linux_amd64/fmt.a
packagefile gong/linshi=/root/.cache/go-build/f3/f363fbc898cebc08cfae6d70ecf58677f7a2159812f31c28a5a507125a3643e8-d
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a
EOF
cd /data/go/src/gong
/usr/local/go/pkg/tool/linux_amd64/compile -o $WORK/b001/_pkg_.a -trimpath "$WORK/b001=>" -p main -complete -buildid Tk7qQb47IMlDTHbYEzR2/Tk7qQb47IMlDTHbYEzR2 -goversion go1.18.1 -c=2 -nolocalimports -importcfg $WORK/b001/importcfg -pack ./abc.go
/usr/local/go/pkg/tool/linux_amd64/buildid -w $WORK/b001/_pkg_.a # internal
cat >$WORK/b001/importcfg.link << 'EOF' # internal
packagefile command-line-arguments=$WORK/b001/_pkg_.a
packagefile fmt=/usr/local/go/pkg/linux_amd64/fmt.a
packagefile gong/linshi=/root/.cache/go-build/f3/f363fbc898cebc08cfae6d70ecf58677f7a2159812f31c28a5a507125a3643e8-d
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a
packagefile errors=/usr/local/go/pkg/linux_amd64/errors.a
packagefile internal/fmtsort=/usr/local/go/pkg/linux_amd64/internal/fmtsort.a
packagefile io=/usr/local/go/pkg/linux_amd64/io.a
packagefile math=/usr/local/go/pkg/linux_amd64/math.a
packagefile os=/usr/local/go/pkg/linux_amd64/os.a
packagefile reflect=/usr/local/go/pkg/linux_amd64/reflect.a
packagefile strconv=/usr/local/go/pkg/linux_amd64/strconv.a
packagefile sync=/usr/local/go/pkg/linux_amd64/sync.a
packagefile unicode/utf8=/usr/local/go/pkg/linux_amd64/unicode/utf8.a
packagefile internal/abi=/usr/local/go/pkg/linux_amd64/internal/abi.a
packagefile internal/bytealg=/usr/local/go/pkg/linux_amd64/internal/bytealg.a
packagefile internal/cpu=/usr/local/go/pkg/linux_amd64/internal/cpu.a
packagefile internal/goarch=/usr/local/go/pkg/linux_amd64/internal/goarch.a
packagefile internal/goexperiment=/usr/local/go/pkg/linux_amd64/internal/goexperiment.a
packagefile internal/goos=/usr/local/go/pkg/linux_amd64/internal/goos.a
packagefile runtime/internal/atomic=/usr/local/go/pkg/linux_amd64/runtime/internal/atomic.a
packagefile runtime/internal/math=/usr/local/go/pkg/linux_amd64/runtime/internal/math.a
packagefile runtime/internal/sys=/usr/local/go/pkg/linux_amd64/runtime/internal/sys.a
packagefile runtime/internal/syscall=/usr/local/go/pkg/linux_amd64/runtime/internal/syscall.a
packagefile internal/reflectlite=/usr/local/go/pkg/linux_amd64/internal/reflectlite.a
packagefile sort=/usr/local/go/pkg/linux_amd64/sort.a
packagefile math/bits=/usr/local/go/pkg/linux_amd64/math/bits.a
packagefile internal/itoa=/usr/local/go/pkg/linux_amd64/internal/itoa.a
packagefile internal/oserror=/usr/local/go/pkg/linux_amd64/internal/oserror.a
packagefile internal/poll=/usr/local/go/pkg/linux_amd64/internal/poll.a
packagefile internal/syscall/execenv=/usr/local/go/pkg/linux_amd64/internal/syscall/execenv.a
packagefile internal/syscall/unix=/usr/local/go/pkg/linux_amd64/internal/syscall/unix.a
packagefile internal/testlog=/usr/local/go/pkg/linux_amd64/internal/testlog.a
packagefile internal/unsafeheader=/usr/local/go/pkg/linux_amd64/internal/unsafeheader.a
packagefile io/fs=/usr/local/go/pkg/linux_amd64/io/fs.a
packagefile sync/atomic=/usr/local/go/pkg/linux_amd64/sync/atomic.a
packagefile syscall=/usr/local/go/pkg/linux_amd64/syscall.a
packagefile time=/usr/local/go/pkg/linux_amd64/time.a
packagefile unicode=/usr/local/go/pkg/linux_amd64/unicode.a
packagefile internal/race=/usr/local/go/pkg/linux_amd64/internal/race.a
packagefile path=/usr/local/go/pkg/linux_amd64/path.a
modinfo "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tcommand-line-arguments\ndep\tgong\t(devel)\t\nbuild\t-compiler=gc\nbuild\tCGO_ENABLED=1\nbuild\tCGO_CFLAGS=\nbuild\tCGO_CPPFLAGS=\nbuild\tCGO_CXXFLAGS=\nbuild\tCGO_LDFLAGS=\nbuild\tGOARCH=amd64\nbuild\tGOOS=linux\nbuild\tGOAMD64=v1\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"
EOF
mkdir -p $WORK/b001/exe/
cd .
/usr/local/go/pkg/tool/linux_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=_TzT60SqVuNzTxt-N6bw/Tk7qQb47IMlDTHbYEzR2/Tk7qQb47IMlDTHbYEzR2/_TzT60SqVuNzTxt-N6bw -extld=gcc $WORK/b001/_pkg_.a
/usr/local/go/pkg/tool/linux_amd64/buildid -w $WORK/b001/exe/a.out # internal
mv $WORK/b001/exe/a.out abc

从上面看出,执行流程主要有以下几个步骤:

  • 创建临时目录:mkdir -p $WORK/b001/
  • 查找依赖信息:cat >$WORK/b001/importcfg << …
  • 执行源代码编译:/usr/local/go/pkg/tool/darwin_amd64/compile …
  • 收集链接库文件:cat >$WORK/b001/importcfg.link << …
  • 生成可执行文件:/usr/local/go/pkg/tool/darwin_amd64/link -o …
  • 移动可执行文件,mv $WORK/b001/exe/a.out abc

go run 与go build不同的是,go run生成可执行程序后,没有移动,而是直接执行了程序

3、golang在将json反序列化到结构体中报错invalid character ‘\x00’ after top-level value

原因:结构体切片的长度大于我们实际要序列化所需要的长度,比如我们在通过bufio.NewReader读取文件后,在通过Read(b []byte)将内容读取到字节切片中b中,此时我们无法预测数据有多少,因此就会提前初始化b这个切片,b := make([]byte,1024),这条命令给切片初始空间为1024字节,如果实际读取到切片中的只有100字节,那么有相当一部分没有使用到,此时如果我们将此字节切片反序列化到结构体中就会报错

下面例子表示读取本地file文件,然后将其反序列化到结构体中,首先查看文件如图:

读取文件的脚本内容如下:

package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

type file struct {
	FileName string `json:"filename"`
	FileSize string `json:"filesize"`
}

func main() {
	//打开文件
	f, err := os.Open("file.txt")
	if err != nil {
		log.Fatal(err)
	}
	//NewReader参数为io Reader接口,Open实现了此接口因此可赋值
	b := bufio.NewReader(f)
	if err != nil {
		log.Fatal(err)
	}
	by := make([]byte, 100) //初始化字节切片并设置容量为100
	i, errs := b.Read(by)   //将数据读取到字节切片c中
	if errs != nil {
		log.Fatal(errs)
	}
	fmt.Println("读入切片中的字节数:",i) //44
	file := &file{}
	errs = json.Unmarshal(by[:i], &file)
	if errs != nil {
		log.Fatal(errs)
	}
	fmt.Println("结构体字段的值:",file.FileName)
}

运行结果如下:

从上图看出,实际写入切片中的字节数为44,但是在初始化切片的时候给的容量为100,实际空间过多,那么在反序列化的时候,就需要先将多余的空间清楚,因此通过by[:i]的截取切片方式获取实际的切片大小再进行反序列化即可

标签