go数据类型-空结构体、空接口、nil

这篇具有很好参考价值的文章主要介绍了go数据类型-空结构体、空接口、nil。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

空结构体

  func main() {
  	a := struct{}{}
  	fmt.Println(unsafe.Sizeof(a))
  	fmt.Printf("%p\n", &a)
  }
  打印 
  0
  0x117f4e0

有经验的开发人员都知道,所有的空结构体是指向一个 zerobase的地址,而且大小为0

一般用来作结合map作为set 或者 在channel中 传递信号。

type void struct{}

type void1 struct {
	a void
}

type void2 struct {
	a void
	b int
}

func main() {
	a0 := void{}
	a1 := void1{}
	a2 := void2{}
	fmt.Println(unsafe.Sizeof(a0))
	fmt.Println(unsafe.Sizeof(a1))
	fmt.Println(unsafe.Sizeof(a2))
	fmt.Printf("void: %p\n", &a0)
	fmt.Printf("void1:%p\n", &a1)
	fmt.Printf("void2: %p\n", &a2)
}
打印:
0
0
8
void: 0x11804e0 zerobase的地址,不是固定,每次运行都会有偏移量
void1:0x11804e0
void2: 0xc00010c008

能看到当一个空结构体中,包含了其他类型的变量,就不指向 zerobase。

runtime的malloc.go中
// base address for all 0-byte allocations
var zerobase uintptr

接口

go中的接口都是隐式的,增加的封装的灵活性,也为阅读源码增加了一些难度。

正常使用: 情况1
type Person interface {
	eat()
}

type Man struct {
	name string
}

func (m Man) eat() {
	fmt.Println(" man eat")
}

func main() {

	var p Person = Man{}
	p.eat()
}

情况2:

func main() {
    // 变成指针 也是正常的
	var p Person = &Man{}
	p.eat()
}

情况3:

  // 指针实现
    func (m *Man) eat() {
    	fmt.Println(" man eat")
    }

    func main() {

    	var p Person = &Man{}
    	p.eat()
    }
也正常

情况4:

// 指针
func (m *Man) eat() {
	fmt.Println(" man eat")
}

func main() {
    // 未加指针
	var p Person = Man{}
	p.eat()
}

报错: cannot use Man{} (value of type Man) as Person value in variable declaration: Man does not implement Person (method eat has pointer receiver) (typecheck)
Man结构未实现,person的方法 eat这个。

网上很多人有讲过这个,这里换个角度归纳下:
只有一种情况下是失败的:当实现接口方法时候,采用指针,使用时候 未采用指针。

原理:在使用 func (m Man) eat() 实现接口时候,编译器会自动加上 带指针的实现 func (m *Man) eat(),反之,不会。所以才会导致情况4失败。

接口的定义

这个数据结构,就是上面例子中变量 p 底层结构。

接口的内部实现:
  type iface struct {
  	tab  *itab 
  	data unsafe.Pointer // 具体实现接口的对象, 就是例子中的 Man结构体的实例
  }

  type itab struct {
  	inter *interfacetype    // 接口自身定义的类型信息,用于定位到具体interface类型
  	_type *_type
  	hash  uint32 // _type.hash的拷贝,用于快速查询和判断目标类型和接口中类型是一致
  	_     [4]byte
  	fun   [1]uintptr // 实现那些接口方法
}

整理下:接口值的底层表示

接口数据使用 runtime.iface 表示

iface记录了数据的地址

iface 中记录了接口类型信息和实现的方法 , 在接口断言时候,用到这些信息。

空接口

空接口的底层实现:
  type eface struct {
  	_type *_type // 只记录数据类型,因为没有方法,所以不用像iface一样,记录接口方法信息
  	data  unsafe.Pointer // 指向数据本身
  }

空接口常用来作为 任意类型的形参 使用。

  例如:
  type any = interface{}
   func Println(a ...any) (n int, err error) {
  	return Fprintln(os.Stdout, a...)
  }

为什么 空接口可以作为任意类型使用?

基于它的底层实现定义:任意的类型,都可以表示为 数据类型 和 数据本身,例如 int 5 ,类型int,数据5

例如在我们使用 fmt.Println(5) 时候,会先将 5 进行组装:

    伪代码:
    a := eface{type : int ,data : 5}
    fmt.Println(a)

整理:空接口的用途

空接口的最大用途是作为任意类型的函数入参
函数调用时,会新生成一个空接口,再传参

nil

定义:

 var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

也就是说nil只能表示 指针、channel、func、interface、map 、slice 这六种类型的空值。

注意这里没有 struct

空结构体是zerobase的空值,不是nil
var a *int
var b map[string]string
var c struct{} 
fmt.Println(a == nil) // true
fmt.Println(b == nil) // true
fmt.Println(c == nil) // mismatched types struct{} and untyped nil
fmt.Println(a == b) // mismatched types *int and map[string]string

都是nil,a和b的值也不同。

有了上面空接口的基础就好理解了, 一个数据,包含了数据类型和数据本身的值。这里a和b都是nil,只是值为nil,但是它们的类型并不一样,所以不等

小结:

nil 是空,并不一定是“空指针”
nil是6种类型的 “零值〞
每种类型的nil是不同的,无法比较

再一个例子:

var a *int
var b interface{}
fmt.Println(a == nil) // true
fmt.Println(b == nil) // true
b = a
fmt.Println(b == nil) // false

回忆下上面 nil的定义,可以表示 interface的空值,但是,通过上面的了解,interface底层实际上是一个结构体eface

nil能作为eface的值,有严格的要求,要求type 和 data 都为空

当把 b = a时候,这时候 type 已经有值,data还为空,但是这个时候 eface 已经是一个结构体了。nil 不能表示 结构体的值,而且这个结构体中成员还不为空。

总结:

  1. nil是多个类型的零值,或者空值
  1. 空结构体的指针和值都不是nil。 指针是zerobase

3.空接口零值是nil,-旦有了类型信息就不是nil文章来源地址https://www.toymoban.com/news/detail-747827.html

到了这里,关于go数据类型-空结构体、空接口、nil的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • go struct结构体之间的转换

    原文链接:https://www.zhoubotong.site/post/94.html 说下背景吧,大家在开发中可能在不同的目录(package)下定义了相同的struct(属性参数完全一样如名字、个数和类型),在方法调用传参数的时候,可能是用到了其中某一个struct的引用。 那么这里就牵扯到相互间的转换:直接上demo: 显然

    2023年04月17日
    浏览(49)
  • 【go语言基础】结构体struct

    主要是敲代码,敲的过程中会慢慢体会。 结构体是用户定义的类型,表示若干字段的集合,目的是将数据整合在一起。 简单的说,类似Java中的实体类。存储某个实体属性的集合。 注意:结构体名字,结构体属性名的首字母大写代表其余的包可以访问该结构体,类似Java中的

    2024年02月13日
    浏览(60)
  • Go语言入门6(struct 结构体)

    ​结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。每个值称为结构体的成员 type + 结构体名 + struct + {成员列表} ​⭐如果结构体成员名字是以大写字母开头的,那么该成员就是导出的。这是Go语言导出规则决 定的。一个结构体可能同时包含导出和

    2023年04月12日
    浏览(43)
  • Go语言结构体struct详解,Go空结构体的这些妙用你知道吗?

    本文详解了Go语言结构体的各个知识点,最后介绍了空结构体的3种妙用。希望对你有帮助。 结构体,是一种自定义的数据类型,由多个数据类型组合而成。用于描述一类事物相关属性 。 定义方式 : 结构体和结构体指针,两者的实例化有所区别 提供多种写法,灵活使用:

    2024年02月01日
    浏览(47)
  • go 笔记 第九章 结构体 struct 声明和使用

    package main import “fmt” type qm struct { name string age int hobby []string home } type home struct { address string } // 给结构体声明方法 func (q qm) song(name string) (ret string) { ret = “惊雷” fmt.Printf(“%v—%v–%v”, q.name, name, q.age) fmt.Println() return ret } func (h home) open() { fmt.Println(“open”) } func main() { v

    2024年02月16日
    浏览(44)
  • Go 中的格式化字符串`fmt.Sprintf()` 和 `fmt.Printf()`

    在 Go 中,可以使用 fmt.Sprintf() 和 fmt.Printf() 函数来格式化字符串,这两个函数类似于 C 语言中的 scanf 和 printf 函数。 fmt.Sprintf() 函数返回一个格式化后的字符串,而不是将其打印到标准输出流中。下面是一个例子: 输出: 在这个例子中,使用了 %s 和 %d 格式化动词来格式化字

    2024年02月09日
    浏览(46)
  • 掌握Go语言:Go语言类型转换,解锁高级用法,轻松驾驭复杂数据结构(30)

    在Go语言中,类型转换不仅仅局限于简单的基本类型之间的转换,还可以涉及到自定义类型、接口类型、指针类型等的转换。以下是Go语言类型转换的高级用法详解: Go语言类型转换的高级用法 1. 自定义类型之间的转换 在Go语言中,可以使用类型别名或自定义类型来创建新的

    2024年04月09日
    浏览(69)
  • Linux系统struct input_event结构体分类型(鼠标、键盘、触屏)详解与例子

    目录 一、概述 二、结构体字段解析 三、不同类型地解释字段  3.1 鼠标事件  3.2 键盘事件  3.3 触摸屏事件 四、使用 struct input_event 读取设备文件的例子 Linux系统是通过 输入子系统 来管理输入设备(如鼠标、键盘、触摸屏、游戏摇杆)的。配置了内核支持且安装对应驱动

    2024年02月16日
    浏览(42)
  • Hive中的复杂数据类型 - array、map、struct

    水善利万物而不争,处众人之所恶,故几于道💦 一、简单数据类型(复习) 官方数据类型详情页 数据类型 描述 范围 tinyint 1byte有符号整数 from -128 to 127 smallint 2byte有符号整数 from -32,768 to 32,767 int 4byte有符号整数 from -2,147,483,648 to 2,147,483,647 bigint 8byte有符号整数 from -9,223,37

    2024年03月12日
    浏览(53)
  • Go 语言 nil 空值

    在 Go 语言中, nil 是一个预定义的标识符,用于表示某些类型的零值或空值。 nil 在 Go 语言中可以表示以下几种类型的零值或空值: 指针类型:表示一个指向空地址的指针,即指针不指向任何有效的内存地址。 接口类型:表示一个空接口,即接口没有关联任何值。 函数类型

    2024年02月11日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包