Go(或 Golang)是一种现代、静态类型、编译型的编程语言,专为构建可扩展、并发和高效的软件而设计。它提供了各种内置的函数和特性,帮助开发人员编写简洁高效的代码。其中包括new()和make()函数,这两个函数乍看起来可能相似,但在 Go 中用于不同的目的,对于内存分配和数据初始化至关重要。
在本博客文章中,我们将探讨new()和make()函数之间的区别,了解何时以及如何有效地使用它们。
new()?和?make()?函数
new()和make()都是 Go 中的内置函数,用于分配内存。然而,它们用于不同的数据类型和场景:
new()?函数:
?new()用于为值类型(例如整数、浮点数、结构体)分配内存,并返回指向新分配的零值的指针。
??它接受一个参数,即类型,并返回该类型的指针。
make()?函数:
?make()用于创建和初始化切片、映射和通道,这些都是 Go 中的引用类型。
??它根据类型的不同接受两个或三个参数,并返回一个已初始化(非零值)的值,可以立即使用。
理解?new()?函数
new()函数的语法非常简单,如下所示:
func?new(Type)?*Type
这里的Type表示我们想要为其分配内存的值的类型。让我们看一个如何使用new()的示例。
在这个示例中,我们使用new()创建了Person结构体的一个新实例,然后使用指针分配值给其字段。
package?main
import?"fmt"
type?Person?struct?{
Name?string
Age??int
}
func?main()?{
//?Using?new()?to?allocate?memory?for?a?Person?struct
p?:=?new(Person)
fmt.Printf("%T\n",?p)
//?Accessing?struct?fields?using?the?pointer
p.Name?=?"Alice"
p.Age?=?30
//?Displaying?the?values
fmt.Println("Name:",?p.Name)
fmt.Println("Age:",?p.Age)
}
这个程序将产生如下所示的输出。
>?go?run?main.go
*main.Person
Name:?Alice
Age:?30理解?make()?函数
make()函数的语法取决于它所用于的类型。
对于切片(Slices)
func?make([]Type,?len,?cap)?[]Type
?Type:切片将保存的元素类型。
?len:切片的初始长度。
?cap:切片的容量,这是可选的,并用于指定底层数组的容量。如果未提供,它默认与长度相同。
使用make()创建切片的示例:
package?main
import?"fmt"
func?main()?{
//?Using?make()?to?create?a?slice?of?integers
numbers?:=?make([]int,?5,?10)
//?Displaying?the?slice's?length,?capacity,?and?values
fmt.Println("Length:",?len(numbers))
fmt.Println("Capacity:",?cap(numbers))
fmt.Println("Values:",?numbers)
//?Using?make()?to?create?a?slice?of?integers
numbersWithoutOptional?:=?make([]int,?5)
//?Displaying?the?slice's?length,?capacity,?and?values
fmt.Println("Length:",?len(numbersWithoutOptional))
fmt.Println("Capacity:",?cap(numbersWithoutOptional))
fmt.Println("Values:",?numbersWithoutOptional)
}
此程序将产生如下输出。
>?go?run?main.go
Length:?5
Capacity:?10
Values:?[0?0?0?0?0]
Length:?5
Capacity:?5
Values:?[0?0?0?0?0]
对于映射(Maps)
func?make(map[KeyType]ValueType,?initialCapacity?int)?map[KeyType]ValueType
?KeyType:映射中键的类型。
?ValueType:与键关联的值的类型。
?initialCapacity:映射的初始容量。这是可选的,但当预先知道元素数量时,可以用于优化性能。
使用make()创建映射的示例:
package?main
import?"fmt"
func?main()?{
//?Using?make()?to?create?a?map?of?string?keys?and?int?values
scores?:=?make(map[string]int)
//?Adding?values?to?the?map
scores["Alice"]?=?95
scores["Bob"]?=?87
//?Displaying?the?map
fmt.Println("Scores:",?scores)
}
>?go?run?main.go
Scores:?map[Alice:95?Bob:87]
对于通道(Channels)
func?make(chan?Type,?capacity?int)?chan?Type
?Type:可以通过通道发送和接收的值的类型。
?capacity:通道的缓冲区大小。如果设置为0,通道是无缓冲的。
使用make()创建通道的示例:
package?main
import?(
"fmt"
"time"
)
func?main()?{
//?Using?make()?to?create?an?unbuffered?channel?of?integers
ch?:=?make(chan?int)
//?Sending?data?into?the?channel?using?a?goroutine
go?func()?{
for?i?:=?1;?i?
ch?
time.Sleep(time.Second)?//?Simulating?some?work?before?sending?the?next?value
}
close(ch)
}()
//?Receiving?data?from?the?channel
for?num?:=?range?ch?{
fmt.Println("Received:",?num)
}
}
>?go?run?main.go
Received:?1
Received:?2
Received:?3
Received:?4
Received:?5结论
在本博客文章中,我们解开了 Go 中的new()和make()函数的谜团,并解释了它们的区别和用途。总结一下:
??使用new()为值类型分配内存,并获取指向零值的指针。
??使用make()创建和初始化切片、映射和通道(引用类型),并指定它们的类型和初始容量。
理解new()和make()之间的区别对于在 Go 中进行高效的内存分配和数据初始化至关重要。正确使用这些函数将在您的 Golang 项目中产生更干净和更优化的代码。愿您编程愉快!
领取专属 10元无门槛券
私享最新 技术干货