Mô tả cơ bản
| Hàm | Công dụng | Đối tượng sử dụng | Giá trị trả về |
|---|---|---|---|
| new | Phân bổ bộ nhớ | Các kiểu giá trị và kiểu do người dùng định nghĩa | Khởi tạo bằng giá trị 0, trả về con trỏ |
| make | Phân bổ bộ nhớ | Các kiểu tham chiếu nội tại (map, slice, channel) | Khởi tạo bằng giá trị 0, trả về chính kiểu tham chiếu |
Tính năng chính của new
Hàm built-in new có thể được minh họa như sau:
func taoMoi(Type) *Type
Hàm này phân bổ bộ nhớ với tham số đầu tiên là kiểu dữ liệu, không phải giá trị. Nó trả về một con trỏ đến giá trị zero của kiểu đã chọn.
Dưới đây là ví dụ tự viết để mô phỏng chức năng của new:
func taoSoNguyen() *int {
var so int
return &so
}
motSo := taoSoNguyen()
Chức năng của hàm trên tương đương với motSo := new(int). Khi đặt tên hàm bắt đầu bằng "tao", chúng ta cũng nên tuân theo quy ước trả về con trỏ kiểu dữ liệu.
Tính năng chính của make
Hàm built-in make có thêm một tham số và cách trả về khác nhau. Định nghĩa mẫu như sau:
func tao(Type, kíchCỡ KiểuSốHọc) Type
Hàm này chuyên dùng để khởi tạo các kiểu map, slice, channel. Trong quá trình biên dịch, việc sử dụng make sẽ gọi các hàm nền khác nhau tùy thuộc vào kiểu dữ liệu:
- Khởi tạo map: Gọi hàm runtime.taoMap
- Khởi tạo slice: Gọi hàm runtime.taoSlice
- Khởi tạo channel: Gọi hàm runtime.taoChan
Hàm nguồn runtime.taoMap
// Đường dẫn: src/runtime/map.go
func taoMap(t *kiểuMap, gợiÝ int, h *hmap) *hmap {
if h == nil {
h = new(hmap)
}
h.hash0 = ngẫuNhiên()
B := uint8(0)
for vượtQuáTảiTrọng(gợiÝ, B) {
B++
}
h.B = B
if h.B != 0 {
h.buckets, nextOverflow = taoDanhSáchThùng(t, h.B, nil)
}
return h
}
Hàm nguồn runtime.taoSlice
// Đường dẫn: src/runtime/slice.go
func taoSlice(kiểu *_type, chiềuDài, dungLượng int) unsafe.Pointer {
mem, overflow := toánHọc.NhânUintptr(kiểu.size, uintptr(dungLượng))
if overflow || mem > maxAlloc || chiềuDài < 0 || chiềuDài > dungLượng {
panic("Chiều dài vượt quá giới hạn")
}
return cấpPhátGc(mem, kiểu, true)
}
Hàm nguồn runtime.taoChan
// Đường dẫn: src/runtime/chan.go
func taoChan(t *kiểuChan, kíchCỡ int) *hchan {
var c *hchan
switch {
case mem == 0:
c = (*hchan)(cấpPhátGc(kíchCỡHchan, nil, true))
c.buf = c.raceaddr()
case elem.ptrdata == 0:
c = (*hchan)(cấpPhátGc(kíchCỡHchan+mem, nil, true))
c.buf = add(unsafe.Pointer(c), kíchCỡHchan)
default:
c = new(hchan)
c.buf = cấpPhátGc(mem, elem, true)
}
c.elemsize = uint16(elem.size)
c.elemtype = elem
c.dataqsiz = uint(kíchCỡ)
}
Tóm tắt
make thực hiện nhiều công việc hơn so với new. Trong khi new chỉ đơn giản phân bổ bộ nhớ, thì make còn quản lý cấu trúc phức tạp hơn và khởi tạo các trường dữ liệu liên quan.