Difference between make and new
In Go, there are two keywords make and new, which can easily be confused when you first start learning Go. Here’s a simple note to clarify their differences.
new
new can be used to initialize generics, and it returns a storage address. Therefore, we usually assign the type returned by new to a pointer variable. It’s particularly important to note that new automatically initializes the type with a zeroed value, meaning a string will be "", numbers will be 0, and channels, functions, maps, slices, etc., will be nil.
Due to this characteristic, if we perform the following operation on a map, we will encounter panic: assignment to entry in nil map.
func main() {
people := new(map[string]string)
p := *people
p["name"] = "Kalan" // panic: assignment to entry in nil map
}
This happens because the initialized map is a nil map, unlike other primitive types which have default values.
When initializing with struct, you can also directly use & to indicate the address being pointed to; the two following methods yield the same result:
type Person struct {
Name string
Age int
}
func main() {
p := &Person{}
p := new(Person)
}
The advantage of the first method is that you can set the Person fields based on the values you want to pass in, while new will directly fill all fields with zeroed values.
make
In contrast to new, make is used to initialize certain special types, such as channels, maps, and slices. Additionally, it’s important to note that make does not return a pointer; if you need a pointer, you should consider using something like new to initialize the type.
func main() {
receiver := make(chan string) // initializes a channel but does not return a pointer
person := make(map[string]string)
people := make([]string, 100) // initializes a string array of length 100
}
It’s worth emphasizing again that make does not return a pointer! The following code will throw an error:
func main() {
person := make(map[string]string)
fmt.Println(*person) // invalid indirect of person
}
Conclusion
make and new are easily confused when you first start learning Go. Sometimes, when you need to pass a pointer as a parameter, you might inadvertently use make. Therefore, understanding the distinction between the two is crucial.
Further Reading
Related Posts
- When Measurement Becomes the Goal: From Window Tax to PR Counts I once wrote a small tool to count how many PRs I had contributed in a quarter, how many reviews I had left, and how many tickets I had closed, hoping to use the numbers to prove my output to my manager. My manager simply said performance is not judged by output alone. Only years later did I understand—when measurement becomes the goal, it is no longer a good measure. From Britain’s window tax and the Hanoi rat bounty to evaluating developers by PR count today, the mechanism is exactly the same.
- Using Cloudflare Images for Image Storage and Transformation Putting an image on a web page is the easiest thing in frontend. But doing it properly — resizing, generating every format, holding up under traffic — turns into a whole solution of its own. I ended up handing all of it to Cloudflare Images and keeping just one original.
- Stop Using Access Keys Already Access Keys are an easily overlooked security risk on AWS. Use OIDC with IAM Roles so GitHub Actions can securely access AWS resources without any secrets.
- Database Primary Keys: AUTO_INCREMENT, UUID, and UUIDv7 Backend developers often have to decide on a primary key: auto increment or UUID? What about collisions? How much faster is UUIDv7 compared with created_at + index? After benchmarking 20 million rows and looking at the design trade-offs, this post gives you the answer.