The Difference Between make and new
In Golang, there are two keywords, make and new, which are often confused when first learning Go. Here is a quick note on them.
new
new can be used to allocate memory for a type, and it returns its memory address. Therefore, we typically use a pointer variable to hold the value allocated by new. It is particularly important to note that new automatically initializes the type with its zero value—meaning strings will be "", numbers will be 0, and channels, funcs, maps, slices, etc., will be nil.
Because of this behavior, performing the following operation on a map will result in 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 that have ready-to-use default values.
When initializing a struct, you can also directly use & to represent the pointer to its address. The two approaches below have the same effect:
type Person struct {
Name string
Age int
}
func main() {
p := &Person{}
p := new(Person)
}
The advantage of using &Person{} is that you can also set custom values for the fields as needed, whereas new fills all fields with their zero values.
make
Unlike new, make is used to initialize specific built-in types such as channels, maps, and slices. Another critical point is that make does not return a pointer. If you need a pointer, you should consider using something like new to initialize the type instead.
func main() {
receiver := make(chan string) // 初始化 channel,但不回傳指標
person := make(map[string]string)
people := make([]string, 100) // 初始化長度為 100 的字串陣列
}
To emphasize once again: 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 easy to confuse when starting out with Golang. Sometimes, when a function requires a pointer parameter, you might accidentally pass the result of make. Knowing the difference between the two is essential in such scenarios.
Further Reading
Related Posts
- When a Measure Becomes a Target: From the Window Tax to Pull Request Counts I once wrote a script to tally how many PRs I contributed in a quarter, how many reviews I left, and how many tickets I closed, hoping to use numbers to prove my output to my manager. My manager simply remarked that performance isn't just about output. Years later, I finally understood—when a measure becomes a target, it ceases to be a good measure. From the British window tax and the Hanoi rat bounty to evaluating developers by PR counts today, the underlying mechanism is exactly the same.
- Using Cloudflare Images for Image Storage and Transformation Putting an image on a webpage is the simplest task in frontend development. But doing it properly—including resizing, generating multiple formats, and withstanding heavy traffic—is actually an entire end-to-end solution. Eventually, I offloaded everything to Cloudflare Images, keeping only a single original image.
- Stop Using AWS Access Keys Access Keys are an easily overlooked security risk in AWS. By pairing OIDC with IAM Roles, GitHub Actions can securely operate AWS resources without storing any secrets.
- Database Primary Keys: AUTO_INCREMENT, UUID, and UUIDv7 Backend developers often face the choice of primary keys: should you use auto-increment or UUID? What about collisions? How does UUIDv7 compare to created_at + index in performance? Here are the design decisions and benchmark results from testing 20 million rows.