GoLang là một ngôn ngữ lập trình hiện đại, kiểu tĩnh, được biên dịch, được thiết kế để xây dựng phần mềm có khả năng mở rộng, đồng thời và hiệu quả. Nó cung cấp nhiều hàm và tính năng tích hợp giúp các nhà phát triển viết mã ngắn gọn và hiệu quả. Trong số đó có các hàm new()
và make()
, thoạt nhìn có vẻ tương tự nhau nhưng phục vụ các mục đích khác nhau trong GoLang và rất quan trọng đối với việc phân bổ bộ nhớ và khởi tạo dữ liệu.
Trong bài viết này, chúng ta sẽ khám phá sự khác biệt giữa các hàm new()
và make()
, và hiểu khi nào và làm thế nào để sử dụng chúng một cách hiệu quả.
new() và make()
new()
và make()
đều là các hàm tích hợp trong GoLang được sử dụng để phân bổ bộ nhớ. Tuy nhiên, chúng được sử dụng cho các kiểu dữ liệu và trường hợp khác nhau:
Hàm new()
new()
được sử dụng để phân bổ bộ nhớ cho các kiểu giá trị như số nguyên, số thực và cấu trúc, và trả về một con trỏ tới giá trị zero được phân bổ mới.
Nó nhận một tham số duy nhất là kiểu và trả về một con trỏ tới kiểu đó.
Hàm make()
make()
được sử dụng để tạo và khởi tạo lát cắt, bản đồ và kênh, là các kiểu tham chiếu trong GoLang.
Nó nhận hai hoặc ba tham số tùy thuộc vào kiểu và trả về một giá trị được khởi tạo (không phải giá trị zero) sẵn sàng để sử dụng.
Hiểu hàm new()
Cú pháp của hàm new()
rất đơn giản, như được hiển thị bên dưới:
func new(Type) *Type
Ở đây, Type đại diện cho kiểu giá trị mà chúng ta muốn phân bổ bộ nhớ. Hãy xem một ví dụ về cách sử dụng new()
.
Trong ví dụ này, chúng ta sử dụng new()
để tạo một thể hiện mới của cấu trúc Person và sau đó gán giá trị cho các trường của nó bằng con trỏ.
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
// Sử dụng new() để phân bổ bộ nhớ cho một cấu trúc Person
p := new(Person)
fmt.Printf("%T\n", p)
// Truy cập các trường cấu trúc bằng con trỏ
p.Name = "Alice"
p.Age = 30
// Hiển thị các giá trị
fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
}
Kết quả đầu ra sẽ là
*main.Person
Name: Alice
Age: 30
Hiểu hàm make()
Cú pháp của hàm make()
phụ thuộc vào kiểu mà nó được sử dụng.
Đối với lát cắt
func make([]Type, len, cap) []Type
- Type: Kiểu của các phần tử mà lát cắt sẽ chứa.
- len: Chiều dài ban đầu của lát cắt.
- cap: Dung lượng của lát cắt, là tùy chọn và được sử dụng để chỉ định dung lượng của mảng cơ sở. Nếu không được cung cấp, nó mặc định bằng với chiều dài.
Dưới đây là một ví dụ về việc tạo một lát cắt bằng make()
:
package main
import "fmt"
func main() {
// Sử dụng make() để tạo một lát cắt các số nguyên
numbers := make([]int, 5, 10)
// Hiển thị chiều dài, dung lượng và giá trị của lát cắt
fmt.Println("Length:", len(numbers))
fmt.Println("Capacity:", cap(numbers))
fmt.Println("Values:", numbers)
// Sử dụng make() để tạo một lát cắt các số nguyên
numbersWithoutOptional := make([]int, 5)
// Hiển thị chiều dài, dung lượng và giá trị của lát cắt
fmt.Println("Length:", len(numbersWithoutOptional))
fmt.Println("Capacity:", cap(numbersWithoutOptional))
fmt.Println("Values:", numbersWithoutOptional)
}
Kết quả đầu ra sẽ là
Length: 5
Capacity: 10
Values: [0 0 0 0 0]
Length: 5
Capacity: 5
Values: [0 0 0 0 0]
Đối với bản đồ
func make(map[KeyType]ValueType, initialCapacity int) map[KeyType]ValueType
- KeyType: Kiểu của khóa trong bản đồ.
- ValueType: Kiểu của giá trị được liên kết với các khóa.
- initialCapacity: Dung lượng ban đầu của bản đồ. Điều này là tùy chọn nhưng có thể được sử dụng để tối ưu hóa hiệu suất khi số lượng phần tử được biết trước.
Dưới đây là một ví dụ về việc tạo một bản đồ bằng make()
:
package main
import "fmt"
func main() {
// Sử dụng make() để tạo một bản đồ có khóa là chuỗi và giá trị là số nguyên
scores := make(map[string]int)
// Thêm giá trị vào bản đồ
scores["Alice"] = 95
scores["Bob"] = 87
// Hiển thị bản đồ
fmt.Println("Scores:", scores)
}
Kết quả đầu ra sẽ là
Scores: map[Alice:95 Bob:87]
Đối với kênh
func make(chan Type, capacity int) chan Type
- Type: Kiểu của các giá trị có thể được gửi và nhận qua kênh.
- capacity: Kích thước bộ đệm của kênh. Nếu đặt thành 0, kênh không được đệm.
Dưới đây là một ví dụ về việc tạo một kênh bằng make()
:
package main
import (
"fmt"
"time"
)
func main() {
// Sử dụng make() để tạo một kênh không được đệm các số nguyên
ch := make(chan int)
// Gửi dữ liệu vào kênh bằng một goroutine
go func() {
for i := 1; i <= 5; i++ {
ch <- i
time.Sleep(time.Second) // Mô phỏng một số công việc trước khi gửi giá trị tiếp theo
}
close(ch)
}()
// Nhận dữ liệu từ kênh
for num := range ch {
fmt.Println("Received:", num)
}
}
Kết quả đầu ra sẽ là
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
Kết luận
Trong bài viết này, chúng ta đã giải mã bí ẩn của các hàm new()
và make()
trong GoLang và giải thích sự khác biệt và trường hợp sử dụng của chúng. Tóm lại:
- Sử dụng
new()
để phân bổ bộ nhớ cho các kiểu giá trị và lấy con trỏ tới giá trị zero. - Sử dụng
make()
để tạo và khởi tạo lát cắt, bản đồ và kênh (kiểu tham chiếu), chỉ định kiểu và dung lượng ban đầu của chúng.
Hiểu sự khác biệt giữa new()
và make()
là rất quan trọng để phân bổ bộ nhớ và khởi tạo dữ liệu hiệu quả trong GoLang. Sử dụng các hàm này một cách chính xác sẽ dẫn đến mã sạch hơn và được tối ưu hóa hơn trong các dự án GoLang của bạn. Chúc bạn lập trình vui vẻ!