Computer >> Máy Tính >  >> Lập trình >> Ruby

Phương pháp Ruby Freeze - Hiểu về khả năng gây đột biến của đối tượng

Một đối tượng có thể thay đổi nghĩa là gì?

Đừng để những từ hoa mỹ làm bạn nhầm lẫn, “ khả năng thay đổi ”Chỉ có nghĩa là trạng thái bên trong của một đối tượng có thể được thay đổi. Đây là mặc định của tất cả các đối tượng, ngoại trừ những đối tượng đã được đóng băng hoặc những thứ nằm trong danh sách các đối tượng đặc biệt.

Nói cách khác, không phải tất cả các đối tượng trong Ruby đều có thể thay đổi được!

Ví dụ :

Nó không có ý nghĩa gì đối với các số hoặc ký hiệu, hoặc thậm chí là true hoặc false (cũng là các đối tượng) để thay đổi.

Số 1 luôn là số 1.

Nhưng các đối tượng khác, đặc biệt là những đối tượng dùng để lưu trữ dữ liệu, như đối tượng Mảng hoặc Hash, sẽ có khả năng thay đổi vì lý do hiệu suất.

Giải pháp thay thế là gì?

Bạn có thể tạo một bản sao mới của một đối tượng với các thay đổi &sau đó trả lại đối tượng mới này, giữ nguyên đối tượng ban đầu.

Nếu mảng là không thể thay đổi và bạn chỉ muốn thay đổi một phần tử của mảng, bạn sẽ phải sao chép tất cả dữ liệu, bao gồm cả các phần tử không thay đổi.

Hãy tưởng tượng bạn phải sao chép một triệu (hoặc nhiều) mảng phần tử mỗi khi bạn phải thực hiện bất kỳ thay đổi nào, không quan trọng bằng cách nào! Không hiệu quả lắm…

Dù sao đi nữa.

Hãy cùng tìm hiểu sâu hơn một chút về cách hoạt động của khả năng thay đổi trong Ruby.

Tính đột biến &biến dưới dạng con trỏ

Có một loại lỗi lập trình được gây ra bởi sự kết hợp của hai nguyên nhân:

  • Đối tượng có thể thay đổi.
  • Thực tế là các biến không chứa dữ liệu trực tiếp mà là tham chiếu đến nơi dữ liệu này được lưu trữ.

Một cách mà những lỗi này tự hiển thị là khi bạn cố gắng tạo "bí danh" cho một biến.

Đây là một ví dụ :

name       = "Peter"
other_name = name

puts other_name
# "Peter"

Trong ví dụ này, cả nameother_name chứa một tham chiếu đến cùng một đối tượng chuỗi. Bạn có thể sử dụng để hiển thị hoặc sửa đổi nội dung của chuỗi này.

Phương pháp Ruby Freeze - Hiểu về khả năng gây đột biến của đối tượng

Sự cố sẽ xuất hiện nếu chúng tôi xử lý other_name giống như một bản sao của chuỗi.

other_name[0] = 'T'

name       # "Teter"
other_name # "Teter"

Vì cả hai biến đều trỏ đến cùng một chuỗi, chúng tôi chỉ thay đổi “Peter” thành “Teter”. Đó là một vấn đề vì có lẽ chúng tôi muốn giữ "Peter" ở lại.

Đối tượng nhân bản

Một cách để giải quyết vấn đề này là sử dụng dup phương pháp.

Điều này sẽ yêu cầu Ruby cung cấp cho bạn một bản sao của đối tượng. Ngoài ra còn có một clone , ngoài việc cung cấp cho bạn một bản sao của đối tượng, nó còn sao chép trạng thái đóng băng &bất kỳ phương thức singleton nào được xác định trên đối tượng.

Hãy xem một ví dụ :

numbers = [1, 2, 3]

more_numbers = numbers.dup
more_numbers << 4

numbers      # [1, 2, 3]
more_numbers # [1, 2, 3, 4]

Trong ví dụ này, bạn có thể thấy cách các số numbers ban đầu mảng vẫn không thay đổi. Thử xóa dup đó gọi vào dòng thứ ba và xem điều gì sẽ xảy ra 🙂

Phương pháp Ruby Freeze

Một cách khác để giữ một đối tượng an toàn trước những thay đổi không mong muốn là 'đóng băng' nó. Mọi đối tượng Ruby đều có thể được đóng băng bằng cách sử dụng freeze phương pháp.

Khi một đối tượng bị đóng băng, bất kỳ nỗ lực nào để thay đổi đối tượng này sẽ dẫn đến RuntimeError ngoại lệ.

Lưu ý:Bạn có thể sử dụng frozen? phương pháp để kiểm tra xem một đối tượng có bị đóng băng hay không.

Ví dụ :

animals = %w( cat dog tiger )
animals.freeze

animals << 'monkey'
# RuntimeError: can't modify frozen Array

Một điều cần lưu ý là điều này sẽ chỉ đóng băng một đối tượng, trong ví dụ này là chính mảng, điều này ngăn chúng ta thêm hoặc lấy bớt các mục khỏi nó. Nhưng các chuỗi bên trong mảng không bị cố định, vì vậy chúng vẫn có thể được thay đổi !

animals[1][0] = 't'
# => ["cat", "tog", "tiger"]

Nếu bạn muốn cố định các chuỗi, bạn cần gọi freeze về họ. Như thế này:animals.each(&:freeze) .

Chuỗi đông lạnh

Các đối tượng có thể thay đổi cũng có tác động đến hiệu suất, đặc biệt là chuỗi. Lý do là có nhiều khả năng trong một chương trình lớn, cùng một chuỗi được sử dụng nhiều lần.

Ruby sẽ tạo một đối tượng mới cho mọi chuỗi, ngay cả khi hai chuỗi trông giống nhau, hay nói cách khác, chúng có cùng ‘nội dung’. Bạn có thể dễ dàng thấy điều này xảy ra trong irb nếu bạn sử dụng object_id phương pháp.

Đây là một ví dụ :

a = 'test'
b = 'test'

a.object_id # 76325640
b.object_id # 76317550

Đây là sự cố vì các đối tượng này đang tiêu thụ thêm bộ nhớ và chu kỳ CPU bổ sung.

Bắt đầu với Ruby 2.1, khi bạn sử dụng chuỗi cố định , Ruby sẽ sử dụng cùng một đối tượng chuỗi. Điều này tránh phải tạo các bản sao mới của cùng một chuỗi. Điều này dẫn đến tiết kiệm bộ nhớ và tăng hiệu suất nhỏ.

Đường ray làm cho rộng rãi sử dụng các chuỗi bị đóng băng vì lý do này. Ví dụ, hãy xem bài PR này.

Điều này đã khiến nhóm phát triển Ruby bắt đầu xem xét việc chuyển các chuỗi thành bất biến các đối tượng theo mặc định. Trên thực tế, Ruby 2.3, mới được phát hành cách đây vài ngày, bao gồm hai cách để kích hoạt tính năng này cho dự án của bạn.

Một là bao gồm # frozen_string_literal: true ở đầu mỗi tệp mà bạn muốn các chuỗi là bất biến. Và cách còn lại là sử dụng đối số dòng lệnh --enable=frozen-string-literal .

Các chuỗi bất biến theo mặc định có thể sẽ xuất hiện trong Ruby 3.0.

Bây giờ đừng điên và bắt đầu đóng băng tất cả các chuỗi trong ứng dụng của bạn. Bạn chỉ muốn thực hiện việc này đối với các chuỗi được sử dụng hàng trăm lần để thấy một số lợi ích . Phải nói rằng, đây là một công cụ mà bạn có thể sử dụng để tìm các chuỗi tiềm năng bị đóng băng.

Biết phương pháp của bạn

Không phải tất cả các phương thức trong một đối tượng có thể thay đổi sẽ thực sự thay đổi đối tượng, ví dụ:phương thức gsub sẽ trả về một chuỗi mới, giữ nguyên chuỗi ban đầu.

Một số phương pháp này có phiên bản thay thế làm thay đổi đối tượng ban đầu tại chỗ, thường hiệu quả hơn. Các phương thức này thường kết thúc bằng biểu tượng dấu chấm than ! để chỉ ra tác dụng của chúng.

Hai ví dụ về các phương thức ‘bang’ này là gsub!map! .

Lưu ý điều này :

Một phương thức kết thúc bằng ! không phải lúc nào đó cũng có nghĩa là "phương pháp thay đổi đối tượng".

Nói một cách tổng quát hơn, ! biểu tượng được sử dụng để biểu thị 'nguy hiểm'. Một ví dụ trong số này là exit! phương thức này sẽ thoát khỏi chương trình ngay lập tức, bỏ qua bất kỳ trình xử lý thoát nào.

Cũng có những phương thức thay đổi đối tượng và không kết thúc bằng ! Biểu tượng. Ví dụ:delete , clear , push , concat và nhiều hơn nữa.

Kết thúc

Khả năng thay đổi có thể là một chủ đề phức tạp, nhưng kể từ khi bạn đọc bài đăng này, bạn đã chuẩn bị tốt hơn nhiều để đối phó với nó. Kiểm tra tài liệu Ruby nếu bạn không chắc phương thức đang hoạt động gì, điều này sẽ giúp bạn tránh được các vấn đề.

Tôi hy vọng bạn thấy bài viết này có nhiều thông tin, vui lòng chia sẻ nó với bạn bè của bạn để họ có thể thưởng thức nó cũng vậy. Cũng tham gia bản tin của tôi bên dưới để bạn không bỏ lỡ nhiều nội dung như thế này khi nó xuất hiện!