Tôi mới sử dụng Go và tôi gặp một chút bất đồng giữa lập trình dựa trên ngăn xếp kiểu C trong đó các biến tự động sống trên ngăn xếp và bộ nhớ được phân bổ sống trên heap và lập trình dựa trên ngăn xếp kiểu Python trong đó điều duy nhất sống trên ngăn xếp là các tham chiếu / con trỏ tới các đối tượng trên heap.
Theo như tôi có thể nói, hai hàm sau cho cùng một đầu ra:
func myFunction() (*MyStructType, error) {
var chunk *MyStructType = new(HeaderChunk)
...
return chunk, nil
}
func myFunction() (*MyStructType, error) {
var chunk MyStructType
...
return &chunk, nil
}
tức là phân bổ một cấu trúc mới và trả lại nó.
Nếu tôi viết rằng trong C, cái đầu tiên sẽ đặt một đối tượng vào heap và cái thứ hai sẽ đặt nó lên ngăn xếp. Cái đầu tiên sẽ trả về một con trỏ cho heap, cái thứ hai sẽ trả về một con trỏ cho stack, nó sẽ bị bốc hơi theo thời gian hàm trả về, đó sẽ là một điều xấu.
Nếu tôi đã viết nó bằng Python (hoặc nhiều ngôn ngữ hiện đại khác trừ C #) thì ví dụ 2 sẽ không thể thực hiện được.
Tôi nhận được rằng rác Go thu thập cả hai giá trị, vì vậy cả hai hình thức trên đều ổn.
Để trích:
Lưu ý rằng, không giống như trong C, hoàn toàn ổn khi trả về địa chỉ của biến cục bộ; bộ lưu trữ liên quan đến biến còn tồn tại sau khi hàm trả về. Trong thực tế, việc lấy địa chỉ của một chữ tổng hợp sẽ phân bổ một thể hiện mới mỗi lần nó được đánh giá, vì vậy chúng ta có thể kết hợp hai dòng cuối cùng này.
Nhưng nó đặt ra một vài câu hỏi.
1 - Trong ví dụ 1, struct được khai báo trên heap. Còn ví dụ 2 thì sao? Đó có phải là khai báo trên ngăn xếp theo cách tương tự như trong C hay nó cũng đi theo đống?
2 - Nếu ví dụ 2 được khai báo trên ngăn xếp, làm thế nào nó tồn tại sau khi hàm trả về?
3 - Nếu ví dụ 2 thực sự được khai báo trên heap, làm thế nào mà các cấu trúc được truyền theo giá trị thay vì tham chiếu? Điểm của con trỏ trong trường hợp này là gì?