标签「go」下的文章

bjmayor发布于2021-08-29

go反射

go标准库-reflect

[TOC]

Golang 接口与反射知识要点

这篇文章以 Go 官方经典博客 The Laws of Reflection 为基础,详细介绍文中涉及的知识点,并有所扩展。

interface

首先,我们谈谈接口类型的内存布局(memory layout),其他基础类型、Struct、Slice、Map、指针类型的内存布局会在以后单独分析。接口变量的值包含两部分内容:赋值给接口类型变量的实际值(concrete value),实际值的类型信息(type descriptor)。两部分在一起构成接口的值(interface value)。

接口变量的这两部分内容由两个字来存储(假设是 32 位系统,那么一个字就是 32 位),第一个字指向 itable (interface table)。itable 表示 interface 和实际类型的转换信息。itable 开头是一个存储了变量实际类型的描述信息,接着是一个由函数指针组成的列表。注意 itable 中的函数和接口类型相对应,而不是和动态类型。例如下面例子,itable 只关联了 Stringer 中定义的 String 方法,而 Binary 中定义的 Get 方法则不在其中。对于每个 interface 和实际类型,只要在代码中存在引用关系, go 就会在运行时为这一对具体的 <Interface, Type> 生成 itable 信息。

第二个字称为 data,指向实际的数据。例子中,赋值语句 var s Stringer = b 实际上对b做了拷贝,而不是对b进行引用。存放在接口变量中的数据大小可能任意,但接口只提供了一个字来专门存储真实数据,所以赋值语句在堆上分配了一块内存,并将该字设置为对这块内存的引用。

阅读全文»

bjmayor发布于2021-08-29

go指针

[TOC]

Go学习笔记–go指针:unsafe.Pointer

简单示例

Go语言是个强类型语言。也就是说Go对类型要求严格,不同类型不能进行赋值操作。指针也是具有明确类型的对象,进行严格类型检查。下面的代码会产生编译错误 :

package main import ( "fmt" ) func main() { u := uint32(32) i := int32(1) fmt.Println(&u, &i) // 打印出地址 p := &i // p 的类型是 *int32 p = &u // &u的类型是 *uint32,于 p 的类型不同,不能赋值 p = (*int32)(&u) // 这种类型转换语法也是无效的 fmt.Println(p) }

阅读全文»

bjmayor发布于2021-08-29

Go语言编程模式实战-左耳朵耗子

[TOC]

《Go语言编程模式实战》

Go编程模式:切片、接口、时间和性能

Slice

首先,我来介绍下 Slice,中文翻译叫“切片”,这个东西在 Go 语言中不是数组,而是一个结构体,其定义如下:

type slice struct { array unsafe.Pointer //指向存放数据的数组指针 len int //长度有多大 cap int //容量有多大 }

一个空的 Slice 的表现如下图所示:

img

阅读全文»

bjmayor发布于2021-08-29

go defer陷阱

[TOC]

golang defer陷阱

测验

下面程序的输出是什么?

package main



//!+f
func main() {
	println(f1())
	println(f2())
	println(f3())

}

func f1() (r int) {
	defer func() {
		r++
	}()
	return 0
}

func f2() (r int) {
	t := 5
	defer func() {
		t = t + 5
	}()
	return t
}

func f3() (r int) {
	defer func(r int) {
		r = r + 5
	}(r)
	return 1
}

答案

如果你的结果是

1
5
1

恭喜你,答对了。这篇文章您不必看了。

如果答错了。请继续阅读

阅读全文»