Ruby: ขยายความด้วยตนเอง


113

extendในทับทิมผมเข้าใจความคิดพื้นฐานของ อย่างไรก็ตามเกิดอะไรขึ้นในส่วนของโค้ดนี้ โดยเฉพาะสิ่งที่extendทำ? เป็นเพียงวิธีที่สะดวกในการสร้างวิธีการอินสแตนซ์ให้เป็นวิธีคลาสหรือไม่? ทำไมคุณถึงทำแบบนี้แทนที่จะระบุเมธอดคลาสตั้งแต่แรก

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

  # what does the next line do?
  extend self
end

คำตอบ:


115

เป็นวิธีที่สะดวกในการสร้างวิธีการอินสแตนซ์ให้เป็นวิธีคลาส แต่คุณยังสามารถใช้มันเป็นเดี่ยวมีประสิทธิภาพมากขึ้น


2
ทำไมซิงเกิลตันแบบนั้นจึงมีประสิทธิภาพมากกว่า?
xuuso

5
ลิงค์ของคุณทำให้เพื่อนของฉันเน่าเสีย
Ulysse BN

1
อัปเดตคำตอบนี้พร้อมลิงก์ไปยัง archive.org
Mike Szyndel

1
คำตอบนี้ไม่เพียงพอเนื่องจากไม่ได้อธิบายว่าคีย์เวิร์ดที่เป็นปัญหาทำให้อินสแตนซ์เมธอดเป็นเมธอดคลาสได้อย่างไร นอกจากนี้ยังไม่ได้อธิบายว่า 'singleton ที่มีประสิทธิภาพมากขึ้น' คืออะไรหรือextend selfเกี่ยวข้องกับสิ่งนั้น
jayqui

29

ในโมดูล self คือคลาสของโมดูลเอง ตัวอย่างเช่น

puts self

จะคืน Rake ดังนั้น

extend self

โดยทั่วไปจะทำให้วิธีการอินสแตนซ์ที่กำหนดไว้ใน Rake พร้อมใช้งานดังนั้นคุณสามารถทำได้

Rake.run_tests

23

สำหรับผมมันก็จะช่วยให้คิดว่าextendเป็นincludeภายในชั้นเดี่ยว (หรือเรียกว่าเมตาหรือระดับไอเกน)

คุณอาจทราบว่าวิธีการที่กำหนดไว้ในคลาสซิงเกิลตันนั้นเป็นวิธีการคลาส:

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

A.x #=> 'x'

ตอนนี้เรารู้ว่าextendจะincludeใช้วิธีการในโมดูลภายในชั้นเดี่ยวและทำให้ให้พวกเขาเป็นวิธีการเรียน:

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

เพื่อหลีกเลี่ยงการลิงก์เน่าบล็อกโพสต์ของ Chris Wanstrath ที่ลิงก์โดย user83510 จะถูกโพสต์ใหม่ด้านล่าง (โดยได้รับอนุญาตจากเขา) ถึงกระนั้นก็ไม่มีสิ่งใดที่จะเหนือกว่าต้นฉบับดังนั้นให้ใช้ลิงค์ของเขาตราบเท่าที่มันยังใช้งานได้


→ singin 'singletons 18 พฤศจิกายน 2551 มีบางอย่างที่ฉันไม่เข้าใจ ตัวอย่างเช่น David Bowie หรือซีกโลกใต้. แต่ไม่มีอะไรที่จะทำให้ฉันรู้สึกแย่เหมือน Singleton ของรูบี้ เพราะจริงๆแล้วมันไม่จำเป็นเลย

นี่คือสิ่งที่พวกเขาต้องการให้คุณทำกับรหัสของคุณ:

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'

แต่ที่บ้า. สู้สุดพลัง

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'

ทำไมไม่? API มีความกระชับมากขึ้นโค้ดง่ายต่อการทดสอบเยาะเย้ยและต้นขั้วและการแปลงเป็นคลาสที่เหมาะสมก็ยังง่ายหากจำเป็น

((ลิขสิทธิ์ควรสิบ chris wanstrath))


อีกวิธีหนึ่งในการหลีกเลี่ยง linkrot คือการใช้บางอย่างเช่น wayback machine - web.archive.orgซึ่งจะเก็บประวัติของหน้าต่างๆในเว็บฉันพบว่ามันค่อนข้างมีประโยชน์ในหลาย ๆ กรณีของ linkrot อยู่ดี
Kem Mason

3

extend selfรวมวิธีการอินสแตนซ์ที่มีอยู่ทั้งหมดเป็นวิธีโมดูล extend Rakeนี้จะเทียบเท่ากับบอกว่า นอกจากนี้ยังเป็นวัตถุของคลาสRakeModule

อีกวิธีหนึ่งในการบรรลุพฤติกรรมที่เท่าเทียมกันคือ:

module Rake
  include Test::Unit::Assertions

  def run_tests # etc.
  end

end 

Rake.extend(Rake)

สิ่งนี้สามารถใช้เพื่อกำหนดโมดูลที่มีอยู่ในตัวด้วยเมธอดส่วนตัว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.