Ruby: mở rộng bản thân


113

Trong Ruby, tôi hiểu ý tưởng cơ bản về extend. Tuy nhiên, điều gì đang xảy ra trong đoạn mã này? Cụ thể là extendlàm gì? Nó chỉ là một cách thuận tiện để biến các phương thức instance thành các phương thức lớp? Tại sao bạn lại làm theo cách này thay vì chỉ định các phương thức lớp ngay từ đầu?

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

  # what does the next line do?
  extend self
end

Câu trả lời:


115

Đó là một cách thuận tiện để biến các phương thức thể hiện thành các phương thức lớp. Nhưng bạn cũng có thể sử dụng nó như một singleton hiệu quả hơn .


2
Tại sao loại singleton đó lại hiệu quả hơn?
xuuso

5
Liên kết của bạn đã làm hỏng bạn của tôi.
Ulysse BN

1
Cập nhật câu trả lời này bằng một liên kết đến archive.org
Mike Szyndel

1
Câu trả lời này không đầy đủ vì nó không giải thích cách từ khóa được đề cập tạo các phương thức cá thể thành phương thức lớp. Nó cũng không giải thích một 'singleton hiệu quả hơn' là gì, hoặc liên quan gì extend selfđến điều đó.
jayqui

29

Trong một mô-đun, self là chính lớp mô-đun. Ví dụ

puts self

sẽ trả lại Rake như vậy,

extend self

về cơ bản làm cho các phương thức cá thể được xác định trong Rake có sẵn cho nó, vì vậy bạn có thể làm

Rake.run_tests

23

Đối với tôi nó luôn luôn giúp nghĩ đến extendnhưinclude bên trong lớp singleton (còn gọi là meta hoặc lớp eigen).

Bạn có thể biết rằng các phương thức được định nghĩa bên trong lớp singleton về cơ bản là các phương thức của lớp:

module A
  class << self
    def x
      puts 'x'
    end
  end
end

A.x #=> 'x'

Bây giờ chúng ta biết rằng, extendsẽ includelà phương pháp trong các mô-đun bên trong lớp singleton và do đó phơi bày chúng như phương pháp lớp:

module A
  class << self
    include A

    def x
      puts 'x'
    end
  end

  def y
    puts 'y'
  end
end

A.x #=> 'x'
A.y #=> 'y'

15

Để tránh bị thối liên kết, bài đăng trên blog của Chris Wanstrath được liên kết bởi user83510 được đăng lại bên dưới (với sự cho phép của anh ấy). Tuy nhiên, không có gì đánh bại được bản gốc, vì vậy hãy sử dụng liên kết của anh ấy miễn là nó tiếp tục hoạt động.


→ singin 'singletons 18 Tháng Mười Một 2008 Có điều tôi không hiểu. David Bowie chẳng hạn. Hoặc Nam bán cầu. Nhưng không có gì làm tôi rối trí như Singleton của Ruby. Bởi vì thực sự, nó hoàn toàn không cần thiết.

Đây là những gì họ muốn bạn làm với mã của bạn:

require 'net/http'

# first you setup your singleton
class Cheat
  include Singleton

  def initialize
    @host = 'http://cheat.errtheblog.com/'
    @http = Net::HTTP.start(URI.parse(@host).host)
  end


  def sheet(name)
    @http.get("/s/#{name}").body
  end
end

# then you use it
Cheat.instance.sheet 'migrations'
Cheat.instance.sheet 'yahoo_ceo'

Nhưng điều đó thật điên rồ. Chiến đấu chống lại quyền lực.

require 'net/http'

# here's how we roll
module Cheat
  extend self

  def host
    @host ||= 'http://cheat.errtheblog.com/'
  end

  def http
    @http ||= Net::HTTP.start(URI.parse(host).host)
  end

  def sheet(name)
    http.get("/s/#{name}").body
  end
end

# then you use it
Cheat.sheet 'migrations'
Cheat.sheet 'singletons'

Bất kỳ tại sao không? API ngắn gọn hơn, mã dễ kiểm tra, mô phỏng và sơ khai hơn, và việc chuyển đổi thành một lớp thích hợp vẫn rất đơn giản nếu có nhu cầu.

((bản quyền phải là mười chris wanstrath))


Một cách khác để tránh linkrot là sử dụng một cái gì đó như máy quay lui - web.archive.org - nó lưu giữ lịch sử các trang trên web, dù sao thì tôi cũng thấy nó khá hữu ích trong nhiều trường hợp của linkrot.
Kem Mason

3

extend selfbao gồm tất cả các phương thức phiên bản hiện có dưới dạng phương thức mô-đun. Điều này tương đương với việc nói extend Rake. Cũng Rakelà một đối tượng của lớp Module.

Một cách khác để đạt được hành vi tương đương sẽ là:

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

end 

Rake.extend(Rake)

Điều này có thể được sử dụng để xác định các mô-đun độc lập với các phương thức riêng.

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.