Ruby: вызов метода класса из экземпляра
в 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
? Похоже, так и должно быть.
9 ответов:
, а не имею в виду буквальное имя класса внутри метода экземпляра, вы можете просто позвонить
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
используя
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"
получить доступ к методу класса внутри метода экземпляра, выполните следующие действия:
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
Вы делаете это правильно. Методы класса (подобные "статическим" методам в 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
Если у вас есть доступ к методу делегирования можно сделать так:
[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
все, что не меняет состояние на класс и экземпляр, потому что вы начнете сталкиваться со странными проблемами столкновения имен. Делать это осторожно и только после того, как вы проверили, ничего не раздавленный.
еще один:
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
вот подход о том, как вы могли бы реализовать
_class
метод, который работает в качествеself.class
для этой ситуации. Примечание: не используйте это в производственном коде, это ради интереса:)от: можете ли вы оценить код в контексте вызывающего абонента в 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:)