Ruby: Örnekten çağrı sınıfı yöntemi


347

Ruby'de, sınıfın örneklerinden birinden sınıf yöntemini nasıl çağırırsınız? Söyle bende

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

satır Truck.default_makevarsayılanı alır. Ama bunu söylemeden söylemenin bir yolu var Truckmı? Olması gerektiği gibi görünüyor.

Yanıtlar:


563

Sınıfın gerçek adına değinmek yerine, bir örnek yöntemi içinde sadece arayabilirsiniz 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

Çıktılar:

Sınıf yöntemi: Foo
Örnek yöntemi: Foo

7
bir örnek bir sınıf yöntemi çağırmak için yakut bazı kısayol görmek istiyorum. ie:> self.class.some_class_method yerine some_class_method
phoet

7
bu doğru cevap olsa da, "self.class" ın "Truck" sınıf adından daha fazla yazılması ve okunması daha kolay bir utanç. oh iyi ....
Matt Connolly

22
@MattConnolly, göreceli, sınıf adınız SalesforceSyncJobdaha kısa ise;)
drewish

29
@MattConnolly, ayrıca self.class, sınıfı yeniden adlandırırsanız arama / değiştirme ihtiyacını ortadan kaldırır.
Gus Shortz

8
@GusShortz true. Ayrıca, bir alt sınıf varsa self.class daha iyi çalışır.
Matt Connolly

183

Kalıtım söz konusu olduğunda kullanmak self.class.blah, kullanmakla aynı DEĞİLDİR 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
Bu, sorunun cevabı yerine kabul edilen cevaba bir cevap gibi görünüyor.
zhon

16
@zohn - true, ancak ne kullanacağınızı düşünürken bu hala yararlı bir bağlam.
Matt Sanders

1
@MattSanders bu durumlarda yalnızca bir yorum kullanır.
nandilugio

1
@hlcs self.class, mirası korumak için doğrudur. olsa make1()tanımlanır Truck, bu referans oluyor BigTruck'ın sınıf yöntemi.
Kaiser Shahid

14

Bir örnek yönteminin içindeki bir sınıf yöntemine erişmek için aşağıdakileri yapın:

self.class.default_make

Sorununuz için alternatif bir çözüm:

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

Şimdi sınıfımızı kullanalım:

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

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

make bir örnek yöntemi olmamalıdır. bir örnek olmaktan ziyade sınıfa bağlı olması gereken bir tür fabrika
phoet

6
@phoet Marka kelimesi bir otomobilin markasını (Toyota, BMW vb . gibi) belirtir englishforums.com/English/AMakeOfCar/crcjb/post.htm . Adlandırma, kullanıcının gereksinimine dayanmaktadır
Harish Shetty

8

Temsilci yöntemine erişiminiz varsa bunu yapabilirsiniz:

[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"

Alternatif olarak, sınıf ve örneğe yetki vermek istediğiniz bir veya iki yöntemden daha fazlasına sahipseniz ve muhtemelen daha temizdir:

[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"

Uyarı kelimesi:

Durumu rastgele delegatesınıf ve örnek olarak değiştirmeyen her şeyi rastgele yapmayın , çünkü garip ad çakışması sorunlarıyla karşılaşmaya başlayacaksınız. Bunu idareli bir şekilde yapın ve kontrol ettikten sonra başka hiçbir şey ezilmez.



5

Doğru şekilde yapıyorsun. Sınıf yöntemleri (C ++ veya Java'daki 'statik' yöntemlere benzer) örneğin bir parçası değildir, bu nedenle doğrudan başvurmaları gerekir.

Bu notta, örneğinizde 'default_make'yi normal bir yöntem haline getirmeniz daha iyi sunulur:

#!/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()

Sınıf yöntemleri, sınıfı kullanan yardımcı program tipi işlevler için daha kullanışlıdır. Örneğin:

#!/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
Bunun default_makebir örnek yöntem olması gerektiğine katılmıyorum . Bu örnekler için daha basit olsa bile, doğru semantik değil - varsayılan, sınıfa ait nesneler değil, sınıfın bir ürünüdür.
Peter

1
@Peter bunu daha basit bir şekilde açıklamak ister misiniz? Sadece Ruby'yi öğreniyorum ve Maha'ın cevapları benim için mükemmel görünüyor.
Marlen TB

1
MarlenT.B @. geriye dönüp baktığımda burada öğrenilecek çok şey olduğundan emin değilim - sadece yöntemi koymak için en iyi yerin nerede olduğunu tartışıyordum ve artık kendi argümanımı güçlü bir şekilde satın almıyorum! :)
Peter

2
Ben de aynı fikirde değilim. Bir şey bir sınıf yöntemi olup olmadığı "yarar" ile ilgisi yoktur. Yöntemin kavramsal olarak sınıfa mı yoksa o sınıfın bir nesnesine mi uygulanacağı ile ilgilidir. Örneğin, her kamyonun farklı bir seri numarası vardır, bu nedenle serial_number bir örnek yöntemidir (karşılık gelen örnek değişkeniyle). Diğer bir araç_türünde ("kamyon" döndürür) bir sınıf yöntemi olmalıdır, çünkü bu tüm kamyonların bir özelliği, belirli bir kamyon değil
vish

3

Bir tane daha:

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

İşte size bir _classyöntemi nasıl uygulayabileceğinize dair bir yaklaşımself.class bu duruma . Not: Bunu üretim kodunda kullanmayın, bu faiz uğruna :)

Kimden: Ruby'de bir arayan bağlamında kod değerlendirebilir misiniz? ve ayrıca 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

Sanırız yanlış oldu, doğrusu şunlar olabilir mi?


-6

Sorunuza benzer şekilde şunları kullanabilirsiniz:

class Truck
  def default_make
    # Do something
  end

  def initialize
    super
    self.default_make
  end
end
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.