golang初始化的一些误区

本文深入探讨了Go语言中各种类型变量的默认初始化值,包括int、string、slice、map、指针、error和struct等,并通过实例展示了如何正确使用这些变量,避免常见的编程陷阱。
最近整理了一下golang初始化的一些注意事项,希望可以帮到初学者
在go中,所有变量都会初始化为空值,不同变量空值不同,所以使用也不一样
变量空值

1 int空值是0
2 string空值是””而不是null或者nil(很多人不理解,这与其他语言确实有一点区别),
3 slice空值是长度为0的nil
4 map空值是nil
5 指针空值是nil
6 error空值是nil
7 bool空值是false
8 struct空值是一个“所有成员都是空值”的空Struct而不是nil

影响

1 可以直接append()一个元素到空Slice里,但是你却不能对空map操作,因为map的空值是 nil
2 对变量进行make(var,length)时,只是len(var)的长度变量变了,并不代表你赋了储值
3 不能粗鲁地判断一个struct是不是nil,因为它永远不可能是nil,所以你可以通过返回一个error来判断是否为空,就像很多go标准库里的做法那样:if err != nil
eg:

func test1(){
	var a []int
	fmt.Println(a == nil)		// true
	
	var b map[int]string
	fmt.Println(b == nil)		// true
	
	mm := make(map[int]string)
	fmt.Println(mm == nil)		// false
	
	var s stu 
	// fmt.Println(stu == nil)  // stu 不能与nil比较
}
func test2(){
	var l []int
	l = append(sl, 1)
	fmt.Println(sl)				// [1]
	
	m := make(map[int]string)
	m[0] = "0"
	fmt.Println(m)				//map[0:0]
	
	//var mm map[int]string
	// mm[0] = "0"				//panic
	//fmt.Println(mm)
}


type stu struct{
	age int
	name string
}
func test3(){
	stus1 := make([]*stu, 1)
	fmt.Println(stus1[0])               // <nil>
	// fmt.Println(stus1[0].age)		// panic,stus1[0]是指针为nil

	stus2 := make([]stu, 1)
	fmt.Println(stus2[0])				// {0 }
	fmt.Println(stus2[0].age)			// 0
}

<think>嗯,用户问的是Go语言中哪些类型是引用类型。我得先回忆一下Go的类型系统。记得Go有值类型和引用类型的区别,对吧?引用类型的话,通常是指那些变量存储的是数据的引用,而不是数据本身。比如切片、映射、通道这些应该算是引用类型。 首先,切片(slice),没错,切片底层其实是一个结构体,包含指向数组的指针、长度和容量。所以当传递切片的时候,传递的是这个结构体的副本,里面的指针还是指向同一个数组,所以修改会影响到底层数组。这就是引用类型的行为。 然后是映射(map),对的,映射也是引用类型。创建映射的时候返回的是一个指向hmap结构的指针,所以当赋值给另一个变量时,两个变量共享同一个映射,修改其中一个会影响另一个。不过要注意,不能直接用未初始化的映射,得用make或者字面量初始化。 接下来是通道(channel),通道也是引用类型。创建通道后,变量实际上是指向hchan结构体的指针。传递通道时,传递的是指针的副本,所以多个变量指向同一个通道,发送和接收数据都是通过这个通道进行的。 还有函数类型(func)应该也算引用类型,不过可能用户更关心的是数据结构类型。函数作为参数传递时,传递的是函数的引用,但可能用户不太会关注这个。另外接口类型(interface)内部包含类型和值的指针,所以行为上类似引用类型,但严格来说是否算引用类型可能有不同说法,可能需要确认一下。 另外指针类型(*T)本身是值类型,因为指针变量存储的是地址的值,传递指针时复制的是地址值,但通过指针可以修改指向的数据。不过指针类型本身不算引用类型,但用户可能会混淆。需要明确区分。 总结一下,Go中的引用类型主要是切片、映射、通道,还有函数和接口可能也被包括在内。但根据官方文档或常见说法,可能更明确的是前三种。需要确保准确,避免误导用户。另外要提醒用户,虽然这些类型是引用类型,但他们的变量本身在传递时是按值传递的,但因为内部有指针,所以表现像引用类型。这点很重要,避免用户误解。 可能用户在学习Go的时候遇到了变量传递的问题,想了解哪些类型在传递时不会被复制数据本身。所以需要详细解释每个类型的行为,并举例说明。比如修改切片元素会影响所有引用该切片的变量,而映射的赋值也会共享底层数据。 还要注意错误处理,比如未初始化的映射是nil,不能直接使用,需要在例子中说明正确用法。同时,可能用户会混淆指针和引用类型,需要明确两者的区别。 最后,结构体是否算引用类型?应该不算,结构体是值类型,但如果结构体包含引用类型的字段,比如切片,那么结构体复制时,切片字段的引用会被共享。这点也可以提一下,帮助用户全面理解。 总之,回答要结构清晰,分点列出每个引用类型,解释其行为,并给出示例。同时澄清可能的误区,比如指针和引用类型的区别,确保用户正确理解。</think>在 Go 语言中,**引用类型**的变量存储的是对底层数据结构的引用(类似于指针),而不是直接持有数据本身。这类类型的特点是: 1. **赋值和传参时传递的是引用**,多个变量可能共享同一份底层数据 2. **修改操作会影响所有引用该数据的变量** 以下是 Go 中的引用类型及其特性分析: --- ### 一、切片(Slice) ```go s1 := []int{1, 2, 3} s2 := s1 // s2 与 s1 共享底层数组 s2[0] = 99 // 修改会影响 s1 fmt.Println(s1) // 输出 [99 2 3] ``` - 底层结构包含:指向数组的指针 + 长度 + 容量 - 修改元素会影响所有共享该切片的变量 - 但**扩容操作**(如 `append` 导致容量不足)会创建新数组,此时与原切片解绑 --- ### 二、映射(Map) ```go m1 := make(map[string]int) m1["a"] = 1 m2 := m1 // m2 与 m1 共享底层哈希表 m2["a"] = 100 // 修改会影响 m1 fmt.Println(m1) // 输出 map[a:100] ``` - 底层实现为哈希表的指针 - 必须使用 `make` 初始化后才能操作 - 并发读写需要加锁(或使用 `sync.Map`) --- ### 三、通道(Channel) ```go ch := make(chan int, 3) chCopy := ch // chCopy 与 ch 指向同一通道 go func() { chCopy <- 42 // 向通道发送数据 }() fmt.Println(<-ch) // 从原通道接收,输出 42 ``` - 用于协程间通信 - 关闭通道会影响所有引用该通道的变量 - 零值为 `nil`,直接操作会导致阻塞 --- ### 四、函数(Function) ```go func foo() {} f1 := foo f2 := f1 // f1 和 f2 指向同一个函数 ``` - 函数变量存储的是函数入口地址的引用 - 函数闭包捕获的变量也遵循引用语义 --- ### 五、接口(Interface) ```go var w io.Writer = os.Stdout wCopy := w // 共享接口的 (type, value) 二元组 w.Write([]byte("hello")) // 两者都输出到标准输出 ``` - 接口值存储类型信息和值的指针 - 空接口 `interface{}`(Go 1.18+ 用 `any`)同理 --- ### ⚠️ 易混淆点:指针类型 虽然指针(`*T`)也存储内存地址,但它是**值类型**: ```go a := 10 p1 := &a p2 := p1 // p2 是 p1 的副本(值拷贝),但都指向同一地址 *p2 = 20 // 通过指针修改会影响 a fmt.Println(a) // 输出 20 ``` - 指针变量本身是值传递(复制的是地址值) - 与引用类型的本质区别在于类型系统层面的处理方式 --- ### 最佳实践建议 1. **修改共享数据时使用互斥锁**(`sync.Mutex`) 2. 对切片进行**防御性复制**(`copy()` 函数)以避免意外修改 3. 通过 `make` 初始化时合理设置容量(对切片/通道) 4. 使用 `defer` 确保关闭资源(如文件、通道) 需要特别注意:Go 的引用类型在参数传递时仍然是**值传递**(复制引用本身),这与 Java/Python 等语言中真正的引用传递有本质区别。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值