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

Hiểu về `self` trong Ruby

Hôm nay tôi muốn nói về self . Nếu bạn đã lập trình Ruby được một thời gian, bạn có thể đã hình thành ý tưởng về self . Bất cứ khi nào bạn đọc hoặc viết một chương trình, self ở đó trong tâm trí bạn.

Nhưng đối với những Rubyists ít kinh nghiệm, hãy self có thể gây khó hiểu. Nó luôn thay đổi, nhưng nó không bao giờ được hiển thị rõ ràng trong mã. Bạn chỉ cần biết.

Rất nhiều vấn đề mà người mới bắt đầu gặp phải là do không hiểu self . Nếu bạn đã từng "đánh mất" một biến phiên bản hoặc phân vân không biết dữ liệu nào hiển thị cho một mixin, thì đó là do bạn không hiểu self trong bối cảnh đó.

Trong bài đăng này, chúng ta sẽ xem xét self trong nhiều tình huống hàng ngày.

self là gì ?

Bạn có thể đã nghe mọi người nói rằng mọi thứ trong Ruby đều là một đối tượng. Nếu điều đó đúng, điều đó có nghĩa là mọi đoạn mã bạn viết "thuộc về" đối tượng nào đó.

self là một biến đặc biệt trỏ đến đối tượng "sở hữu" đoạn mã đang thực thi. Ruby sử dụng self mọi nơi:

  • Đối với các biến ví dụ:@myvar
  • Đối với phương pháp và tra cứu liên tục
  • Khi xác định các phương thức, lớp và mô-đun.

Về lý thuyết, self là khá rõ ràng. Nhưng trong thực tế, rất dễ xảy ra những tình huống khó khăn. Đó là lý do tại sao tôi viết bài này.

Ví dụ về self

Bây giờ chúng ta sẽ xem xét một số ví dụ. Nếu những cái đầu tiên có vẻ quá cơ bản đối với bạn, hãy tiếp tục đọc. Chúng được nâng cao hơn.

Bên trong của một phương thức phiên bản

Trong đoạn mã dưới đây, reflect là một phương thức thể hiện. Nó thuộc về đối tượng chúng tôi đã tạo qua Ghost.new . Vì vậy, self chỉ vào đối tượng đó.

class Ghost
  def reflect
    self
  end
end

g = Ghost.new
g.reflect == g # => true

Bên trong của một phương thức lớp

Đối với ví dụ này, reflect là một phương thức lớp của Ghost . Với các phương thức của lớp, chính lớp đó "sở hữu" phương thức. self chỉ vào lớp học.

class Ghost
  def self.reflect
    self
  end
end

Ghost.reflect == Ghost # => true

Nó hoạt động tương tự với các phương thức "lớp" bên trong mô-đun. Ví dụ:

module Ghost
  def self.reflect
    self
  end
end 
Ghost.reflect == Ghost # => true

Hãy nhớ rằng, các lớp và mô-đun được coi như các đối tượng trong Ruby. Vì vậy, hành vi này không khác nhiều so với hành vi của phương thức cá thể mà chúng ta đã thấy trong ví dụ đầu tiên.

Bên trong định nghĩa lớp hoặc mô-đun

Một tính năng của Ruby khiến nó trở nên phù hợp với các khung công tác như Rails là bạn có thể thực thi mã tùy ý bên trong các định nghĩa lớp và mô-đun. Khi bạn đặt mã bên trong định nghĩa lớp / mô-đun, nó sẽ chạy giống như bất kỳ mã Ruby nào khác. Sự khác biệt thực sự duy nhất là giá trị của self .

Như bạn có thể thấy bên dưới, self trỏ đến lớp hoặc mô-đun đang trong quá trình được xác định.

class Ghost
  self == Ghost # => true
end 

module Mummy
  self == Mummy # => true
end 

Các phương thức mixin bên trong

Các phương thức kết hợp hoạt động giống như các phương thức lớp hoặc trường hợp "bình thường" khi nói đến self . Điều này thật ý nghĩa. Nếu không, mixin sẽ không thể tương tác với lớp mà bạn đã trộn nó vào.

Phương thức phiên bản

Mặc dù reflect phương thức đã được xác định trong mô-đun, self của nó là thể hiện của lớp mà nó đã được trộn vào.

module Reflection
  def reflect
    self
  end
end 

class Ghost
  include Reflection
end

g = Ghost.new
g.reflect == g # => true

Phương thức lớp

Khi chúng tôi extend một lớp để trộn trong các phương thức của lớp, self hoạt động chính xác như nó hoạt động trong các phương thức lớp bình thường.

module Reflection
  def reflect
    self
  end
end 

class Ghost
  extend Reflection
end

Ghost.reflect == Ghost # => true

Bên trong siêu kính

Rất có thể bạn đã thấy phím tắt phổ biến này để xác định nhiều phương thức lớp cùng một lúc.

class Ghost
  class << self 
    def method1
    end

    def method2
    end
  end
end

Lớp class << foo cú pháp thực sự khá thú vị. Nó cho phép bạn truy cập siêu kính của một đối tượng - còn được gọi là "lớp singleton" hoặc "lớp eigenclass." Tôi dự định sẽ đề cập sâu hơn đến kính thiên văn trong một bài đăng trong tương lai. Nhưng hiện tại, bạn chỉ cần biết rằng metaclass là nơi Ruby lưu trữ các phương thức dành riêng cho một đối tượng cụ thể.

Nếu bạn truy cập self từ bên trong class << foo khối, bạn sẽ có được siêu kính.

class << "test"
  puts self.inspect
end

# => #<Class:#<String:0x007f8de283bd88>

Bên ngoài bất kỳ lớp nào

Nếu bạn đang chạy mã bên ngoài bất kỳ lớp nào, Ruby vẫn cung cấp self . Nó trỏ tới "main", là một bản sao của Object :

puts self.inspect # => main