Đáng ngạc nhiên, tất cả 10 câu trả lời ở đây nói cùng một điều. '::' là toán tử phân giải không gian tên và đúng vậy. Nhưng có một vấn đề mà bạn phải nhận ra về toán tử phân giải không gian tên khi nói đến thuật toán tra cứu liên tục . Khi Matz phác họa trong cuốn sách của mình, 'Ngôn ngữ lập trình Ruby', việc tra cứu liên tục có nhiều bước. Đầu tiên, nó tìm kiếm một hằng số trong phạm vi từ vựng trong đó hằng số được tham chiếu. Nếu nó không tìm thấy hằng số trong phạm vi từ vựng, thì nó sẽ tìm kiếm hệ thống phân cấp thừa kế . Do thuật toán tra cứu liên tục này, bên dưới chúng tôi nhận được kết quả mong đợi:
module A
module B
PI = 3.14
module C
class E
PI = 3.15
end
class F < E
def get_pi
puts PI
end
end
end
end
end
f = A::B::C::F.new
f.get_pi
> 3.14
Trong khi F kế thừa từ E, mô-đun B nằm trong phạm vi từ vựng của F. Do đó, các thể hiện F sẽ đề cập đến hằng số PI được xác định trong mô-đun B. Bây giờ nếu mô-đun B không xác định PI, thì các thể hiện F sẽ đề cập đến PI hằng số được định nghĩa trong siêu lớp E.
Nhưng điều gì sẽ xảy ra nếu chúng ta sử dụng '::' thay vì các mô-đun lồng nhau? Chúng ta sẽ nhận được kết quả tương tự? Không!
Bằng cách sử dụng toán tử phân giải không gian tên khi xác định các mô đun lồng nhau, các mô đun và các lớp lồng nhau không còn nằm trong phạm vi từ vựng của các mô đun bên ngoài của chúng. Như bạn có thể thấy bên dưới, PI được định nghĩa trong A :: B không nằm trong phạm vi từ vựng của A :: B :: C :: D và do đó chúng ta nhận được hằng số chưa được khởi tạo khi cố gắng tham chiếu PI trong phương thức ví dụ get_pi:
module A
end
module A::B
PI = 3.14
end
module A::B::C
class D
def get_pi
puts PI
end
end
end
d = A::B::C::D.new
d.get_pi
NameError: uninitialized constant A::B::C::D::PI
Did you mean? A::B::PI