Ruby:インスタンスからクラスメソッドを呼び出す


347

Rubyでは、そのクラスのインスタンスの1つからクラスメソッドをどのように呼び出しますか?私が持っていると言います

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ますか?あるべきようです。

回答:


563

クラスのリテラル名を参照するのではなく、インスタンスメソッド内で呼び出すことができます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

出力:

クラスメソッド:Foo
インスタンスメソッド:Foo

7
インスタンスからクラスメソッドを呼び出すためのルビーのショートカットが欲しいです。ie:> some_class_methodの代わりにself.class.some_class_method
phoet

7
これは正しい答えですが、「self.class」の方がクラス名「Truck」よりも入力が多く、読みにくいのは残念です。まあ...
マットコノリー

22
@MattConnolly、それは相対的で、クラス名がSalesforceSyncJobそれよりも短い場合は短くなります;)
drewish

29
@MattConnollyを使用self.classすると、クラスの名前を変更した場合でも、検索/置換の必要がなくなります。
Gus Shortz 2013年

8
@GusShortz正しい。また、サブクラスがある場合は、self.classがより適切に機能します。
マットコノリー2013年

183

使用するには、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" 

58
これは、質問への回答ではなく、受け入れられた回答への応答のようです。
zhon

16
@zohn-正しいですが、これは、何を使用するかを検討するときに依然として有用なコンテキストです。
マットサンダーズ

1
@MattSandersはそれらの場合にコメントを使用します。
nandilugio 2016

1
@hlcs self.classは継承を保持するのに適切です。でmake1()定義されていますがTruck、それはBigTruckのクラスメソッドを参照しています。
カイザー

Class_name.method_nameは完璧に機能します
Houda M

14

インスタンスメソッド内のクラスメソッドにアクセスするには、次の操作を行います。

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

makeはインスタンスメソッドであってはなりません。これは一種のファクトリーであり、インスタンスではなくクラスにバインドする必要があります
phoet

6
@phoetメイクワードは、車のメーカーを示します(トヨタ、BMWなど)englishforums.com/English/AMakeOfCar/crcjb/post.htm。命名法はユーザーの要件に基づいています
Harish Shetty

8

デリゲートメソッドへのアクセス権がある場合、これを行うことができます。

[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つ以上ある場合は、おそらくよりクリーンです。

[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奇妙な名前の衝突の問題に遭遇し始めるので、状態をクラスとインスタンスに変更しないすべてのものをランダムにランダムにしないでください。これを慎重に行い、他の何も押しつぶされていないことを確認した後にのみ実行してください。



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

2
これdefault_makeはインスタンスメソッドであるべきだと思います。これらの例の方が単純であっても、それは正しいセマンティクスではありません。デフォルトはクラスの製品であり、クラスに属するオブジェクトではありません。
Peter

1
@ピーター、それをもっと簡単に説明してもらえますか?私はRubyを学んでいるだけで、マハの答えは完璧に思えます。
Marlen TB 2012

1
@ MarlenT.B。振り返ってみると、ここで学べることが多すぎるとは思いません。メソッドを配置するのに最適な場所はどこであるかだけを議論していたため、自分の主張をこれほど強く買うことはありません。:)
Peter

2
私も同意しません。何かがクラスメソッドであるかどうかは、「ユーティリティ」とは関係ありません。それは、メソッドが概念的にクラスに適用されるのか、そのクラスのオブジェクトに適用されるのかについてです。たとえば、トラックごとにシリアル番号が異なるため、serial_numberはインスタンスメソッドです(対応するインスタンス変数を使用)。他の車両の種類(戻り「トラック」)は、すべてのトラックのプロパティではなく、特定のトラックであるため、クラスメソッドであるべきで
vish

3

もう一つ:

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

1

この状況_classで機能するメソッドを実装する方法についてのアプローチを次に示しますself.class。注:本番コードではこれを使用しないでください。これは、興味を引くためのものです:)

From: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のパッチを提出することです:)


-6

あなたの質問と同様に、あなたは使うことができます:

class Truck
  def default_make
    # Do something
  end

  def initialize
    super
    self.default_make
  end
end
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.