
在Go语言中,new和make是两种核心的内存分配与初始化机制。new用于为任意类型分配零值内存并返回其指针,而make则专为切片、映射和通道这三种引用类型设计,用于分配并初始化其内部数据结构,返回的是已初始化的值而非指针。理解两者的差异及其适用场景,对于编写高效且符合Go惯例的代码至关重要。
Go语言中的内存分配与初始化方式
go语言提供了多种方式来分配内存和初始化值,包括:
复合字面量(Composite Literals):如 Point{2, 3} 或 &Point{2, 3},后者结合了分配和初始化,并返回一个指向新分配结构的指针。局部变量地址:&someLocalVar,获取一个已存在局部变量的地址。new 函数:分配零值内存并返回指针。make 函数:为切片、映射、通道分配并初始化内存。
理解这些方式的细微差别,尤其是new和make,是掌握Go语言内存管理的基石。
new 函数:零值分配与指针返回
new是一个内建函数,其主要作用是为指定类型分配内存,并将这块内存清零(即初始化为该类型的零值),然后返回一个指向这块内存的指针。new函数可以应用于Go语言中的任何类型。
语法: new(Type)返回值: *Type (指向新分配的零值内存的指针)
示例:
立即学习“go语言免费学习笔记(深入)”;
package mainimport "fmt"type Point struct { X, Y int}func main() { // 1. 分配一个整型并获取其指针 ptrInt := new(int) fmt.Printf("new(int) -> 类型: %T, 值: %v, 指向的值: %vn", ptrInt, ptrInt, *ptrInt) // 类型: *int, 值: 0xc000018080, 指向的值: 0 // 2. 分配一个Point结构体并获取其指针 ptrPoint := new(Point) fmt.Printf("new(Point) -> 类型: %T, 值: %v, 指向的值: %vn", ptrPoint, ptrPoint, *ptrPoint) // 类型: *main.Point, 值: 0xc000018088, 指向的值: {0 0} // 3. 对比使用复合字面量获取指针 // &Point{} 同样分配并返回一个指向Point零值的指针 // &Point{2, 3} 分配并初始化,然后返回指针 initializedPointPtr := &Point{2, 3} fmt.Printf("&Point{2, 3} -> 类型: %T, 值: %v, 指向的值: %vn", initializedPointPtr, initializedPointPtr, *initializedPointPtr) // 类型: *main.Point, 值: 0xc000018090, 指向的值: {2 3} // 注意:&int 是非法的,不能直接获取类型字面量的地址 // var i int; &i 是合法的,但不如 new(int) 简洁 var i int ptrI := &i fmt.Printf("var i int; &i -> 类型: %T, 值: %v, 指向的值: %vn", ptrI, ptrI, *ptrI) // 类型: *int, 值: 0xc000018098, 指向的值: 0}
从示例中可以看出,new为所有类型分配内存并将其初始化为零值,然后返回一个指向该零值的指针。
make 函数:特定类型初始化与值返回
make也是一个内建函数,但它与new有着本质的区别。make仅用于创建并初始化切片(slice)、映射(map)和通道(channel)这三种引用类型。它不仅分配内存,还会初始化这些类型内部的数据结构,使其可以立即使用。make返回的是这些类型的值,而不是指针。
语法:
make([]Type, length, capacity) (切片)make(map[KeyType]ValueType) (映射)make(chan Type, capacity) (通道)返回值: Type (已初始化的切片、映射或通道值)
示例:
立即学习“go语言免费学习笔记(深入)”;
package mainimport "fmt"func main() { // 1. 使用 make 创建一个切片 // make([]int, 5) 创建一个长度为5,容量为5的int切片,元素初始化为零值 slice := make([]int, 5) fmt.Printf("make([]int, 5) -> 类型: %T, 值: %v, 长度: %d, 容量: %dn", slice, slice, len(slice), cap(slice)) // 类型: []int, 值: [0 0 0 0 0], 长度: 5, 容量: 5 // 2. 使用 make 创建一个映射 // make(map[string]int) 创建一个空的map myMap := make(map[string]int) myMap["apple"] = 1 fmt.Printf("make(map[string]int) -> 类型: %T, 值: %v, 长度: %dn", myMap, myMap, len(myMap)) // 类型: map[string]int, 值: map[apple:1], 长度: 1 // 3. 使用 make 创建一个通道 // make(chan int) 创建一个无缓冲的int通道 // make(chan int, 3) 创建一个带3个缓冲的int通道 ch := make(chan int, 2) fmt.Printf("make(chan int, 2) -> 类型: %T, 值: %vn", ch, ch) // 类型: chan int, 值: 0xc0000180c0 // 错误示例:make 不能用于非切片、映射、通道类型 // make(Point) // 编译错误: cannot make type Point // make(int) // 编译错误: cannot make type int}
make函数返回的是一个已经初始化好的值,可以直接使用。它为这些引用类型分配了底层的存储空间,并设置了必要的内部结构(如切片的长度、容量,映射的哈希表,通道的缓冲区等)。
new 与 make 的核心区别与设计哲学
通过上述分析,我们可以总结出new和make的关键差异:
用途为任意类型分配零值内存仅用于切片、映射、通道的分配与初始化返回值返回指向零值内存的指针 (*Type)返回已初始化的值 (Type)功能仅分配内存并清零分配内存并初始化内部数据结构,使其可立即使用适用类型所有类型(基本类型、结构体、数组、指针等)仅限切片([]T)、映射(map[K]V)、通道(chan T)
为什么Go语言要设计两个不同的函数?
最初,Go语言的开发者也考虑过将new和make合并成一个单一的内建函数。然而,最终决定保持它们的分离,主要出于以下考量:
语义清晰性:new的语义是“分配一块内存并清零,然后给我它的地址”。这对于所有类型都是一致的。make的语义是“创建一个可用的切片/映射/通道,并返回这个值”。这包含了更复杂的初始化逻辑,不仅仅是简单的内存分配。操作的本质不同:new(T)返回的是*T,它是一个指针。make(T, args)返回的是T,它是一个值。例如,make([]int, 10)返回的是一个切片值,而不是指向切片的指针。如果只有一个函数,例如ALLOC(Type, …),那么用户需要记住何时需要加*来获取指针,何时直接返回类型值。
// 假设只有一个ALLOC函数p := ALLOC(*chan int) // 需要 * 才能得到 *chan intc := ALLOC(chan int) // 直接得到 chan ints := ALLOC([]int, 10) // 直接得到 []intp_int := ALLOC(*int) // 需要 * 才能得到 *int
这种方式容易让新手混淆,何时需要*,何时不需要。
避免混淆:两个函数的设计,使得开发者能够根据所需创建的类型和期望的返回结果(指针或值)直观地选择正确的函数,从而降低了学习曲线和出错的可能性。new用于分配“零值”的内存,而make用于“构建”一个可用的引用类型实例。
总结与实践建议
当你需要为任何类型分配内存,并希望获得一个指向该类型零值的指针时,请使用 new。 例如,new(int)、new(MyStruct)。当你需要创建并初始化切片、映射或通道这三种引用类型时,请使用 make。 make会为你设置好这些类型所需的内部结构,使其立即可用。例如,make([]int, 10)、make(map[string]string)、make(chan bool)。对于结构体,如果想同时分配内存并初始化字段,通常使用复合字面量 &MyStruct{Field: value} 更为简洁和常见。 它既分配了内存,又进行了初始化,并返回一个指针。
理解new和make的职责分离是Go语言设计哲学的一部分,它强调了明确性和简洁性,帮助开发者更好地管理内存和编写清晰的代码。
以上就是Go语言内存分配:深入解析new与make的异同与应用场景的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1400650.html
微信扫一扫
支付宝扫一扫