2010-03-27 161 views
282

調用類的方法在Ruby中,你怎麼罵從該類的實例中的一個類的方法?假設我有紅寶石:從實例

class Truck 
    def self.default_make 
    # Class method. 
    "mac" 
    end 

    def initialize 
    # Instance method. 
    Truck.default_make # gets the default via the class's method. 
    # But: I wish to avoid mentioning Truck. Seems I'm repeating myself. 
    end 
end 

Truck.default_make檢索默認值。但是有沒有一種方式說這個,而不提Truck?似乎應該有。

回答

459

而不是指類的文字名稱,實例方法中,你可以叫self.class.whatever

class Foo 
    def self.some_class_method 
     puts self 
    end 

    def some_instance_method 
     self.class.some_class_method 
    end 
end 

print "Class method: " 
Foo.some_class_method 

print "Instance method: " 
Foo.new.some_instance_method 

輸出:

 
Class method: Foo 
Instance method: Foo 
+5

我想看到一些ruby中的快捷方式來調用一個實例的類方法。即:> some_class_method,而不是self.class.some_class_method – phoet 2011-12-28 11:22:57

+7

,雖然這是正確的答案,但很遺憾「self.class」比班級名稱「Truck」更易打字並且不易讀。哦,好吧...... – 2012-01-11 11:18:38

+14

@MattConnolly,它是相對的,如果你的類名是'SalesforceSyncJob',那麼它就更短了;) – drewish 2013-02-27 21:00:40

5

你正在做的是正確的方式。類方法(類似於C++或Java中的「靜態」方法)不是實例的一部分,所以它們必須直接引用。

關於這一點,在你的例子你會得到更好的服務使得「default_make」一個普通的方法:

#!/usr/bin/ruby 

class Truck 
    def default_make 
     # Class method. 
     "mac" 
    end 

    def initialize 
     # Instance method. 
     puts default_make # gets the default via the class's method. 
    end 
end 

myTruck = Truck.new() 

類方法是使用該類的實用型功能更加有用。例如:

#!/usr/bin/ruby 

class Truck 
    attr_accessor :make 

    def default_make 
     # Class method. 
     "mac" 
    end 

    def self.buildTrucks(make, count) 
     truckArray = [] 

     (1..count).each do 
      truckArray << Truck.new(make) 
     end 

     return truckArray 
    end 

    def initialize(make = nil) 
     if(make == nil) 
      @make = default_make() 
     else 
      @make = make 
     end 
    end 
end 

myTrucks = Truck.buildTrucks("Yotota", 4) 

myTrucks.each do |truck| 
    puts truck.make 
end 
+1

我不同意'default_make'應該是一個實例方法。即使這些示例更簡單,它也不是正確的語義 - 默認值是類的產品,而不是屬於該類的對象。 – Peter 2010-03-27 06:26:13

+1

@Peter你會不會更簡單地解釋一下?我只是在學習Ruby,而Maha的答案對我來說似乎很完美。 – 2012-03-26 03:04:06

+1

@ MarlenT.B。回頭看,我不確定這裏有太多可以學習的東西 - 我只是在爭論最好的地方放置這個方法,而且我不再強烈地支持我自己的觀點! :) – Peter 2012-03-29 06:57:50

6

訪問類方法的實例方法中,執行以下操作:

self.class.default_make 

這裏是你的問題的替代解決方案:

class Truck 

    attr_accessor :make, :year 

    def self.default_make 
    "Toyota" 
    end 

    def make 
    @make || self.class.default_make 
    end 

    def initialize(make=nil, year=nil) 
    self.year, self.make = year, make 
    end 
end 

現在讓我們使用我們的類:

t = Truck.new("Honda", 2000) 
t.make 
# => "Honda" 
t.year 
# => "2000" 

t = Truck.new 
t.make 
# => "Toyota" 
t.year 
# => nil 
+0

make不應該是一個實例方法。它更像是一種工廠,應該被綁定到班級而不是實例上 – phoet 2011-12-28 11:21:30

+4

@phoet make word表示汽車的製造(如在豐田,寶馬等)http://www.englishforums.com/English /AMakeOfCar/crcjb/post.htm。命名是基於用戶的要求 – 2011-12-28 20:56:42

156

使用self.class.blah是不一樣的使用ClassName.blah,當涉及到繼承。

class Truck 
    def self.default_make 
    "mac" 
    end 

    def make1 
    self.class.default_make 
    end 

    def make2 
    Truck.default_make 
    end 
end 


class BigTruck < Truck 
    def self.default_make 
    "bigmac" 
    end 
end 

ruby-1.9.3-p0 :021 > b=BigTruck.new 
=> #<BigTruck:0x0000000307f348> 
ruby-1.9.3-p0 :022 > b.make1 
=> "bigmac" 
ruby-1.9.3-p0 :023 > b.make2 
=> "mac" 
+52

這似乎是對接受答案的迴應,而不是對問題的回答。 – zhon 2013-12-07 17:34:10

+12

@zohn - true,但在考慮使用什麼時,這仍然是有用的上下文。 – 2016-01-19 07:34:34

+0

@MattSanders只是在這些情況下使用評論。 – nandinga 2016-08-03 21:01:58

5

如果您有機會獲得委託方法,你可以這樣做:

[20] pry(main)> class Foo 
[20] pry(main)* def self.bar 
[20] pry(main)*  "foo bar" 
[20] pry(main)* end 
[20] pry(main)* delegate :bar, to: 'self.class' 
[20] pry(main)* end 
=> [:bar] 
[21] pry(main)> Foo.new.bar 
=> "foo bar" 
[22] pry(main)> Foo.bar 
=> "foo bar" 

或者,也可能更清潔,如果你有更多的,那麼你要委託類&實例的方法或兩個:

[1] pry(main)> class Foo 
[1] pry(main)* module AvailableToClassAndInstance 
[1] pry(main)*  def bar 
[1] pry(main)*  "foo bar" 
[1] pry(main)*  end 
[1] pry(main)* end 
[1] pry(main)* include AvailableToClassAndInstance 
[1] pry(main)* extend AvailableToClassAndInstance 
[1] pry(main)* end 
=> Foo 
[2] pry(main)> Foo.new.bar 
=> "foo bar" 
[3] pry(main)> Foo.bar 
=> "foo bar" 

一個忠告:

不要只是隨機delegate所有不會改變狀態的類和實例,因爲你會開始遇到奇怪的名稱衝突問題。謹慎地做到這一點,只有在你沒有檢查任何東西后纔會被壓扁。

1

下面介紹如何實施_class方法,該方法對self.class適用於這種情況。注意:不要在生產代碼中使用此,這是利益着想:)

來源:Can you eval code in the context of a caller in Ruby?http://rubychallenger.blogspot.com.au/2011/07/caller-binding.html

# Rabid monkey-patch for Object 
require 'continuation' if RUBY_VERSION >= '1.9.0' 
class Object 
    def __; eval 'self.class', caller_binding; end 
    alias :_class :__ 
    def caller_binding 
    cc = nil; count = 0 
    set_trace_func lambda { |event, file, lineno, id, binding, klass| 
     if count == 2 
     set_trace_func nil 
     cc.call binding 
     elsif event == "return" 
     count += 1 
     end 
    } 
    return callcc { |cont| cc = cont } 
    end 
end 

# Now we have awesome 
def Tiger 
    def roar 
    # self.class.roar 
    __.roar 
    # or, even 
    _class.roar 
    end 
    def self.roar 
    # TODO: tigerness 
    end 
end 

也許正確的答案是提交補丁的Ruby :)

2

還有一個:

class Truck 
    def self.default_make 
    "mac" 
    end 

    attr_reader :make 

    private define_method :default_make, &method(:default_make) 

    def initialize(make = default_make) 
    @make = make 
    end 
end 

puts Truck.new.make # => mac 
+0

Ruby版本2.1 – Alexey 2014-06-17 20:35:37

-6

類似你的問題,你可以使用:

class Truck 
    def default_make 
    # Do something 
    end 

    def initialize 
    super 
    self.default_make 
    end 
end