Hằng số trong Ruby là gì?
Hằng là một loại biến luôn bắt đầu bằng một chữ cái viết hoa. Chúng chỉ có thể được xác định bên ngoài trong số các phương thức, trừ khi bạn sử dụng lập trình siêu hình.
Hằng số được sử dụng cho các giá trị không được phép thay đổi, nhưng Ruby không ngăn bạn thay đổi chúng.
Chúng trông như thế này :
FRUIT = "orange"
Bây giờ :
Bởi vì hằng số là một chủ đề quan trọng, chúng tôi sẽ khám phá chúng một cách chi tiết trong bài viết này!
Cách xác định hằng số
Một hằng số không yêu cầu bất kỳ ký hiệu hoặc cú pháp đặc biệt nào để khai báo. Bạn chỉ cần đặt chữ cái đầu tiên thành chữ hoa.
Sau đây là các hằng số hợp lệ :
ABC = 1 Goo = 2 Foo = 3
Lưu ý rằng bạn không thể xác định các hằng số bên trong một phương thức.
Bạn sẽ nhận được thông báo lỗi khó hiểu này :
def the_method ABC = 1 end # "dynamic constant assignment"
Vì vậy, chỉ cần xác định hằng số của bạn bên ngoài các phương thức, thông thường, chúng tôi muốn có các định nghĩa hằng số ở đầu lớp của bạn để chúng được hiển thị rõ ràng.
class RubyBlog URL = "rubyguides.com" AUTHOR = "Jesus Castello" end
Sau đó, bạn có thể truy cập các hằng số này bên trong các phương thức của lớp hoặc bên ngoài lớp bằng cú pháp sau:
p RubyBlog::AUTHOR # "Jesus Castello"
Chúng ta sẽ nói thêm một chút về phạm vi của hằng số ở phần sau trong bài đăng này, vì vậy hãy chú ý theo dõi!
Lỗi liên tục chưa được khởi tạo
Một lỗi phổ biến mà bạn có thể gặp phải là:
puts Foo # "uninitialized constant Foo (NameError)"
Tôi muốn bạn dịch lỗi này thành "hằng số không tìm thấy".
Một điểm quan trọng để hiểu lỗi này là các lớp Ruby là hằng số.
Ví dụ :
Array String Hash
Chúng là hằng số vì chữ cái đầu tiên là chữ hoa.
Khi bạn xác định một lớp, những gì bạn thực sự đang làm là tạo một Class
đối tượng, được gán cho một hằng số.
Hằng số trở thành tên lớp.
Tại sao điều này lại quan trọng?
Bởi vì lý do rất có thể khiến bạn gặp lỗi "hằng số chưa được khởi tạo" là bạn quên require
một tệp hoặc đá quý xác định hằng số.
Hoặc có thể bạn chỉ viết sai chính tả tên của hằng số.
Vì vậy, hãy để mắt đến điều đó.
Các hằng số có thể thay đổi
Giống như tôi đã đề cập trong phần giới thiệu, các hằng số Ruby có thể thay đổi.
Ví dụ :
ABC = 1 ABC = 2
Nhưng bạn sẽ thấy thông báo cảnh báo này:
2: warning: already initialized constant ABC
Chương trình của bạn sẽ vẫn hoạt động tốt, nhưng bạn muốn tránh điều này.
Không có cách nào để ngăn một hằng số thay đổi vì các biến trong Ruby không phải là vùng chứa, chúng chỉ đơn giản là con trỏ đến các đối tượng.
Hoặc nhãn, nếu bạn thích.
Điều tốt nhất bạn có thể làm là sử dụng các đối tượng không thể thay đổi.
Ví dụ :
AUTHOR = "Jesus Castello".freeze AUTHOR << "o" # RuntimeError: can't modify frozen String
Bài viết có liên quan :Khả năng thay đổi của Ruby và phương pháp đóng băng.
Trong ví dụ này, bạn vẫn có thể thay đổi những gì AUTHOR
hằng số đang trỏ đến, điều duy nhất freeze
bảo vệ bạn khỏi việc thay đổi chính đối tượng.
Phương thức không đổi
Có một số phương pháp dành riêng để làm việc với hằng số:
Phương pháp | Mô tả |
---|---|
hằng số | Trả về một mảng ký hiệu đại diện cho các hằng số được xác định trong một lớp |
const_get | Trả về giá trị cho một hằng số. Lấy biểu tượng hoặc chuỗi làm tham số |
const_set | Đặt giá trị cho một hằng số. Lấy hai tham số:tên hằng làm ký hiệu và giá trị không đổi |
const_missing | Giống với method_missing nhưng đối với hằng số |
const_defined? | Trả về true nếu một hằng số nhất định (dưới dạng ký hiệu) đã được xác định |
remove_const | Xóa một hằng số |
private_constant | Đặt một hằng số riêng tư để nó không thể được truy cập bên ngoài lớp với Class::ABC cú pháp |
Có một số thủ thuật lập trình siêu hình mà bạn có thể thực hiện bằng các phương pháp này.
Ví dụ :
mô-đunmodule Food class Bacon; end class Chocolate; end end puts "Classes defined inside #{Food}:" puts Food.constants
Ngoài ra, bạn có thể sử dụng một chuỗi như "Array" và lấy lớp thực tế:
array_class = Object.const_get("Array")
Nhưng hãy cẩn thận với điều đó vì người dùng có thể chèn mã nếu chuỗi đến từ params
hoặc một số hình thức nhập liệu khác của người dùng.
Trong Rails, có phương thức Constantize về cơ bản thực hiện const_get
cho bạn, nhưng hãy nhớ rằng nó không thực hiện bất kỳ kiểm tra bảo mật nào.
CheatSheet
Phạm vi không đổi của Ruby
Khi bạn tạo một hằng số bên ngoài bất kỳ lớp nào, ở cấp cao nhất của mã của bạn, hằng số đó sẽ có sẵn ở bất cứ đâu.
Các hằng số cũng có sẵn trong các lớp con.
class A FOO = 1 end class B < A def foo puts FOO end end B.constants # [:FOO]
Các hằng số được định nghĩa bên ngoài một mô-đun hoặc lớp lồng nhau cũng có sẵn bên trong các lớp lồng nhau.
module Food STORE_ADDRESS = "The moon" class Bacon def foo; puts STORE_ADDRESS; end end end fb = Food::Bacon.new fb.foo # "The moon"
Trộn mô-đun
Các hằng số từ các mô-đun được kết hợp cũng có sẵn:
module Mixin A = 123 end class Product include Mixin puts A end # 123
Lưu ý rằng điều này hoạt động khi bao gồm mô-đun, nó sẽ không hoạt động nếu bạn đang mở rộng nó.
Ví dụ :
class Product extend Mixin puts A end # uninitialized constant Product::A
Ngoài ra :
Khi bạn sử dụng một phương thức đã được bao gồm từ một mô-đun, Ruby sẽ tìm kiếm các hằng số bắt đầu từ nơi phương thức đó được định nghĩa.
Ví dụ :
module Parent def print_value VALUE end end class Child include Parent VALUE = 1 end # Works p Child::VALUE # uninitialized constant Parent::VALUE p Child.new.print_value
Một điều cần ghi nhớ!
Lồng mô-đun
Tôi muốn cho bạn xem thêm một ví dụ với các lớp lồng nhau (tương tự cho các mô-đun).
class A FOO = 1 end class A::B class C puts FOO end end
Lưu ý A::B
ký hiệu ở đây, mà chúng tôi đã cố gắng sử dụng làm phím tắt. Nhưng vấn đề là lớp C
sẽ không có quyền truy cập vào FOO
trực tiếp.
Vì lý do đó, bạn muốn gắn bó với loại lồng này:
class A FOO = 1 end class A class B class C puts FOO end end end
Trong ví dụ đầu tiên, bạn vẫn có thể thực hiện ::A::FOO
để truy cập hằng số, nhưng nếu tên lớp thay đổi thì bạn sẽ gặp lỗi.
::A::FOO
này cú pháp hoạt động vì nó yêu cầu Ruby tìm trong phạm vi cấp cao nhất, nơi các hằng số như Array
&String
được xác định.
Video
Tóm tắt
Bạn đã học về hằng số Ruby, một loại biến có một số hành vi thú vị. Bạn có thể thay đổi giá trị của một hằng số nhưng nó sẽ in ra một cảnh báo.
Bạn cũng biết rằng tên lớp là hằng số và bạn nên tránh const_get
với đầu vào của người dùng.
Nếu bạn thích bài đăng này đừng quên chia sẻ nó để nhiều người có thể hiểu cách hoạt động của hằng số.