Bản sao sâu trong Ruby

Tram Ho

Việc copy giá trị trong Ruby thường cần thiết. Điều này có vẻ đơn giản nếu object được copy đơn giản. Nhưng nếu bạn phải copy một object với cấu trúc gồm nhiều mảng hoặc hash, bạn sẽ gặp một số vấn đề.

Objects and References

Để hiểu chuyện gì đang xảy ra, hãy xem vài ví dụ đơn giản. Đầu tiên, phép gán sử dụng trong Ruby.

Ở đây phép gán đang lấy giá trị của a và gán giá trị đó cho b sử dụng phép gán. Bất kỳ thay đổi nào đến a sẽ không phản liên quan đến b. Nhưng hãy đến ví dụ phức tạp hơn chút nữa?

Trước khi chạy các câu lệnh trên, thử đoán output là gì và tại sao. Không giống như ví dụ trước, khi thay a thay đổi thì b cũng thay đổi theo, nhưng lí do là gì? Bởi vì mảng trong Ruby không thuộc loại POD. Phép gán không copy giá trị mà chỉ đơn giản là copy tham chiếu đến mảng ban đầu mà b trỏ tới trên vùng nhớ. Lúc này ab đang trỏ đến cùng một đối tượng mảng, bất kỳ thay đổi nào lên mỗi biến thì biến còn lại sẽ thấy được trên biến kia.

Bây giờ, bạn đã biết tại sao copy các đối tượng non-trivial với những tham chiếu đến đối tượng khác có thể gặp khó khăn. Nếu đơn giản copy một object nghĩa là bạn đang copy một tham chiếu từ object đó đến object sâu hơn, vì vậy bạn copy đó gọi là “shllow copy”

dup và clone

Ruby cung cấp 2 method phục vụ cho việc copy. Object#dup sẽ tạo ra “shallow copy” của object. Để làm được, method dup sẽ gọi method initialize__copy của class đó. Ở một vài class giống như Array, nó sẽ khởi tạo một array mới với cùng số phần tử như mảng gốc. Tuy nhiên nó không phải là deep copy.
Xem ví dụ sau:

Cái gì bên trong đang xảy ra? Method Array#initialize_copy sẽ tạo một bản sao của một mảng, nhưng bản copy đó là shallow copy. Nếu bạn có bất kỳ loại non-POD trong mảng của bạn, sử dụng dup chỉ deep copy một phần. Nó chỉ deep copy mảng đầu tiên (mảng cha), bất kỳ các mảng sâu hơn(bên trong), hash hoặc các object khác sẽ chỉ là shallow copy.

Có một method khác là clone, nó thực hiện điều tương tự như method dup với khác biệt quan trọng: Người ta mong đợi những object sẽ ghi đè method này bằng một method khác có thể thực hiện deep copy.

Trong thực tế điểu này có nghĩa là gì? Mỗi class bạn có thể định nghĩa một method clone để tạo ra deep copy object của class đó. Có nghĩa bạn phải viết method clone cho mỗi class của các object bạn muốn copy.

Marshalling

Marshalling một object là cách để nói serializing một object. Nói cách khác, biến object thành một luồng ký tự có thể được ghi vào file, sau đó unmarshal hoặc unserialize để lấy ra cùng object. Điều này được áp dụng để deep copy bất kỳ object nào.

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo