lớp << thành ngữ tự trong Ruby


873

Điều gì class << selflàm trong của Ruby ?


35
Có một bài viết rất hay về chủ đề này được viết bởi Yehuda Katz: yehudakatz.com/2009/11/15/ory và Yugui: yugui.jp/articles/846
Andrei

3
Một đẹp siêu Điều ở đây: integralist.co.uk/posts/eigenclass.html
Saman Mohamadi

2
Tôi đang thấy điều này bên trong một mô-đun, điều đó có làm cho nó khác đi không? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken

@FullDecent Nó không tạo ra sự khác biệt vì mọi thứ trong Ruby là một đối tượng bao gồm các mô-đun và các lớp.
Aaron

Câu trả lời:


912

Đầu tiên, class << foocú pháp mở ra foolớp đơn (eigenclass). Điều này cho phép bạn chuyên môn hóa hành vi của các phương thức được gọi trên đối tượng cụ thể đó.

a = 'foo'
class << a
  def inspect
    '"bar"'
  end
end
a.inspect   # => "bar"

a = 'foo'   # new object, new singleton class
a.inspect   # => "foo"

Bây giờ, để trả lời câu hỏi: class << selfmở ra self's lớp singleton, do đó phương pháp có thể được định nghĩa lại cho hiện tại selfđối tượng (mà bên trong một cơ thể lớp hoặc mô-đun là lớp hoặc mô-đun riêng của mình ). Thông thường, điều này được sử dụng để định nghĩa các phương thức lớp / mô-đun ("tĩnh"):

class String
  class << self
    def value_of obj
      obj.to_s
    end
  end
end

String.value_of 42   # => "42"

Điều này cũng có thể được viết như một tốc ký:

class String
  def self.value_of obj
    obj.to_s
  end
end

Hoặc thậm chí ngắn hơn:

def String.value_of obj
  obj.to_s
end

Khi bên trong một định nghĩa hàm, selftham chiếu đến đối tượng mà hàm đang được gọi với. Trong trường hợp này, class << selfmở lớp singleton cho đối tượng đó; một cách sử dụng đó là để thực hiện bộ máy nhà nước của một người nghèo:

class StateMachineExample
  def process obj
    process_hook obj
  end

private
  def process_state_1 obj
    # ...
    class << self
      alias process_hook process_state_2
    end
  end

  def process_state_2 obj
    # ...
    class << self
      alias process_hook process_state_1
    end
  end

  # Set up initial state
  alias process_hook process_state_1
end

Vì vậy, trong ví dụ trên, mỗi trường hợp StateMachineExampleđã được đặt process_hookbí danh process_state_1, nhưng lưu ý làm thế nào trong trường hợp sau, nó có thể xác định lại process_hook( selfchỉ, không ảnh hưởng đến các StateMachineExampletrường hợp khác ) process_state_2. Vì vậy, mỗi lần người gọi gọi processphương thức (gọi là có thể xác định lại process_hook), hành vi sẽ thay đổi tùy thuộc vào trạng thái của nó.


22
@ Jörg: +1 để chỉnh sửa (Tôi muốn SO cung cấp khả năng nâng cấp các chỉnh sửa; oh tốt). Đó thực sự là cách sử dụng phổ biến hơn class << self, để tạo các phương thức lớp / mô-đun. Tôi có thể sẽ mở rộng về việc sử dụng đó class << self, vì đó là một cách sử dụng thành ngữ hơn nhiều.
Chris Jester-Young

4
gsub ( "eigenclass", "singleton class"), xem phương pháp sắp tới! redmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune

4
Nó thực sự khó hiểu để tham khảo asingleton_classtừ a'lớp s (sau khi thay đổi inspect) là một biến thể độc đáo của Stringlớp. Nếu nó thay đổi Stringlớp singleton, nó sẽ ảnh hưởng đến tất cả các Stringtrường hợp khác . Điều kỳ lạ hơn nữa là nếu sau này bạn mở lại Stringđể xác định lại inspectthì avẫn sẽ nhận được những thay đổi mới.
Old Pro

1
@OldPro Tôi vẫn thích cái tên eigenclass, vì (tôi tin) Matz cũng vậy. Nhưng, tôi không thể làm hài lòng tất cả mọi người, tôi đoán vậy.
Chris Jester-Young

5
Tôi tìm thấy biểu thức, "mở lớp đơn của một đối tượng" - điều mà tôi đã đọc nhiều lần trước đây - mơ hồ. Theo hiểu biết của tôi, không nơi nào trong các tài liệu Ruby là "mở" một lớp được định nghĩa, mặc dù tất cả chúng ta đều có ý tưởng về ý nghĩa của nó. Có class << selfnghĩa là bất cứ điều gì nhiều hơn giá trị của selfđược đặt bằng với lớp singleton trong phạm vi của khối không?
Cary Swoveland

34

Tôi tìm thấy một lời giải thích siêu đơn giản về class << self, Eigenclassvà các loại phương pháp khác nhau.

Trong Ruby, có ba loại phương thức có thể được áp dụng cho một lớp:

  1. Phương pháp sơ thẩm
  2. Phương pháp đơn
  3. Phương thức lớp

Các phương thức sơ thẩm và phương thức lớp gần như tương tự với các ngôn ngữ lập trình khác.

class Foo  
  def an_instance_method  
    puts "I am an instance method"  
  end  
  def self.a_class_method  
    puts "I am a class method"  
  end  
end

foo = Foo.new

def foo.a_singleton_method
  puts "I am a singletone method"
end

Một cách khác để truy cập Eigenclass(bao gồm các phương thức singleton) là với cú pháp sau ( class <<):

foo = Foo.new

class << foo
  def a_singleton_method
    puts "I am a singleton method"
  end
end

bây giờ bạn có thể định nghĩa một phương thức singleton cho chính selflớp Foođó trong ngữ cảnh này:

class Foo
  class << self
    def a_singleton_and_class_method
      puts "I am a singleton method for self and a class method for Foo"
    end
  end
end

4
thực ra các phương thức Singleton và các phương thức Class là như nhau, cả hai đều tồn tại trong lớp singleton. bạn có thể sử dụng foo.singleton_class.instance_methods(false)để kiểm tra.
Damon Yuan

22

Thông thường, các phương thức thể hiện là các phương thức toàn cầu. Điều đó có nghĩa là chúng có sẵn trong tất cả các trường hợp của lớp mà chúng được định nghĩa. Ngược lại, một phương thức singleton được thực hiện trên một đối tượng.

Ruby lưu trữ các phương thức trong các lớp và tất cả các phương thức phải được liên kết với một lớp. Đối tượng mà một phương thức singleton được định nghĩa không phải là một lớp (nó là một thể hiện của một lớp). Nếu chỉ các lớp có thể lưu trữ các phương thức, làm thế nào một đối tượng có thể lưu trữ một phương thức singleton? Khi một phương thức singleton được tạo, Ruby sẽ tự động tạo một lớp ẩn danh để lưu trữ phương thức đó. Các lớp ẩn danh này được gọi là siêu dữ liệu, còn được gọi là các lớp đơn hoặc eigenclass. Phương thức singleton được liên kết với siêu dữ liệu, lần lượt, được liên kết với đối tượng mà phương thức singleton được xác định.

Nếu nhiều phương thức singleton được định nghĩa trong một đối tượng, tất cả chúng đều được lưu trữ trong cùng một siêu dữ liệu.

class Zen
end

z1 = Zen.new
z2 = Zen.new

class << z1
  def say_hello
    puts "Hello!"
  end
end

z1.say_hello    # Output: Hello!
z2.say_hello    # Output: NoMethodError: undefined method `say_hello'…

Trong ví dụ trên, lớp << z1 thay đổi bản thân hiện tại để trỏ đến siêu dữ liệu của đối tượng z1; sau đó, nó định nghĩa phương thức say_hello trong siêu dữ liệu.

Các lớp cũng là các đối tượng (các thể hiện của lớp dựng sẵn có tên là Class). Các phương thức lớp không có gì khác hơn các phương thức singleton được liên kết với một đối tượng lớp.

class Zabuton
  class << self
    def stuff
      puts "Stuffing zabuton…"
    end
  end
end

Tất cả các đối tượng có thể có siêu dữ liệu. Điều đó có nghĩa là các lớp cũng có thể có siêu dữ liệu. Trong ví dụ trên, lớp << tự sửa đổi bản thân để nó trỏ đến siêu dữ liệu của lớp Zabuton. Khi một phương thức được định nghĩa mà không có bộ thu rõ ràng (lớp / đối tượng mà phương thức sẽ được xác định), nó được định nghĩa ngầm trong phạm vi hiện tại, nghĩa là giá trị hiện tại của bản thân. Do đó, phương thức công cụ được định nghĩa trong siêu dữ liệu của lớp Zabuton. Ví dụ trên chỉ là một cách khác để định nghĩa một phương thức lớp. IMHO, tốt hơn là sử dụng cú pháp def self.my_new_clas_method để xác định các phương thức lớp, vì nó làm cho mã dễ hiểu hơn. Ví dụ trên được đưa vào để chúng tôi hiểu những gì đang xảy ra khi chúng tôi bắt gặp lớp << cú pháp tự.

Thông tin bổ sung có thể được tìm thấy tại bài viết này về Ruby Classes .


15

Lớp << điều gì làm:

class Hi
  self #=> Hi
  class << self #same as 'class << Hi'
    self #=> #<Class:Hi>
    self == Hi.singleton_class #=> true
  end
end

[nó làm self == thing.singleton_class trong bối cảnh của khối] .


Điều.singleton_group là gì?

hi = String.new
def hi.a
end

hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true

hiđối tượng kế thừa nó #methodstừ nó #singleton_class.instance_methodsvà sau đó từ nó #class.instance_methods.
Ở đây chúng ta đã hi's lớp singleton phương pháp dụ :a. Nó có thể đã được thực hiện với lớp << hi thay vào đó.
hi#singleton_classcó tất cả các phương pháp dụ hi's #classcó, và có thể một số chi tiết ( :aở đây).

[phương pháp ví dụ của điều #class #singleton_class có thể được áp dụng trực tiếp vào điều. khi ruby ​​nhìn thấy thing.a, trước tiên, nó tìm kiếm: một định nghĩa phương thức trong thing.singleton_group.instance_methods và sau đó trong thing. class.instance_methods]


Nhân tiện - họ gọi lớp singleton của đối tượng == metaclass == eigenclass .


3

Phương thức sing singleton là phương thức chỉ được xác định cho một đối tượng.

Thí dụ:

class SomeClass
  class << self
    def test
    end
  end
end

test_obj = SomeClass.new

def test_obj.test_2
end

class << test_obj
  def test_3
  end
end

puts "Singleton's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods

Phương pháp của Singleton

kiểm tra


Các phương thức test_obj của Singleton

kiểm tra_2

kiểm tra_3


1

Trong thực tế nếu bạn viết bất kỳ phần mở rộng C nào cho các dự án Ruby của mình thì thực sự chỉ có một cách để xác định phương thức Mô-đun.

rb_define_singleton_method

Tôi biết việc tự kinh doanh này chỉ mở ra tất cả các loại câu hỏi khác để bạn có thể làm tốt hơn bằng cách tìm kiếm từng phần.

Đối tượng đầu tiên.

foo = Object.new

Tôi có thể làm một phương pháp cho foo không?

Chắc chắn rồi

def foo.hello
 'hello'
end

Tôi phải làm gì với nó?

foo.hello
 ==>"hello"

Chỉ là một đối tượng khác.

foo.methods

Bạn nhận được tất cả các phương thức Object cộng với phương thức mới của bạn.

def foo.self
 self
end

foo.self

Chỉ là đối tượng foo.

Hãy thử xem điều gì sẽ xảy ra nếu bạn tạo foo từ các Đối tượng khác như Class và Module. Các ví dụ từ tất cả các câu trả lời rất hay để chơi nhưng bạn phải làm việc với các ý tưởng hoặc khái niệm khác nhau để thực sự hiểu những gì đang diễn ra với cách viết mã. Vì vậy, bây giờ bạn có rất nhiều điều khoản để xem xét.

Singleton, Class, Module, self, Object và Eigenclass đã được đưa lên nhưng Ruby không đặt tên cho Model Model theo cách đó. Nó giống như Metaclass hơn. Richard hoặc __why cho bạn thấy ý tưởng ở đây. http://viewourcecode.org/why/hacking/ectingMetac gốmClearly.html Và nếu bạn bị thổi bay thì hãy thử tìm kiếm Mô hình đối tượng Ruby trong tìm kiếm. Hai video mà tôi biết trên YouTube là Dave Thomas và Peter Cooper. Họ cố gắng giải thích khái niệm đó quá. Dave đã mất một thời gian dài để có được nó vì vậy đừng lo lắng. Tôi cũng vẫn đang làm việc với nó. Tại sao tôi lại ở đây? Cảm ơn câu hỏi của bạn. Cũng hãy xem thư viện tiêu chuẩn. Nó có một Mô-đun Singleton giống như một FYI.

Điều này là khá tốt. https://www.youtube.com/watch?v=i4uiyWA8eFk

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.