루비 : 인스턴스에서 클래스 메소드 호출


347

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있습니까? 있어야 할 것 같습니다.

답변:


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

7
인스턴스에서 클래스 메소드를 호출하는 루비의 단축키를보고 싶습니다. 예 :이> 대신 self.class.some_class_method의 some_class_method
phoet

7
이것이 정답이지만 "self.class"가 클래스 이름 "Truck"보다 타이핑하기 쉽고 읽기가 쉽지 않다는 것은 부끄러운 일입니다. 잘 ..
Matt Connolly

22
@MattConnolly, 그것은 상대적입니다. 만약 당신의 클래스 이름이 SalesforceSyncJob짧다면;)
drewish

29
또한 @MattConnolly를 사용 self.class하면 클래스 이름을 바꾸는 경우 검색 / 바꾸기를 할 필요가 없습니다.
거스 쇼츠

8
@GusShortz true. 또한 하위 클래스가 있으면 self.class가 더 잘 작동합니다.
매트 코놀리

183

사용 self.class.blahClassName.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 December

16
@zohn-true, 그러나 이것은 무엇을 사용 해야할지 고려할 때 여전히 유용한 컨텍스트입니다.
Matt Sanders

1
이 경우 @MattSanders는 주석을 사용합니다.
nandilugio

1
self.class상속을 유지하려면 @hlcs 가 정확합니다. make1()에 정의되어 있지만 Truck참조하는 BigTruck클래스 메소드입니다.
Kaiser Shahid

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는 인스턴스 메소드가 아니어야합니다. 그것은 인스턴스가 아닌 클래스에
묶어야

6
@phoet make 단어는 자동차의 제조사를 나타냅니다 (Toyota, BMW 등) englishforums.com/English/AMakeOfCar/crcjb/post.htm . 명명법은 사용자 요구 사항을 기반으로합니다
Harish Shetty

8

delegate 메소드에 액세스 할 수있는 경우 다음을 수행 할 수 있습니다.

[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이상한 이름 충돌 문제가 발생하기 때문에 상태를 클래스 및 인스턴스로 변경하지 않는 모든 것을 무작위로하지 마십시오 . 이 작업은 드물게 수행하고 다른 사항을 확인한 후에 만 ​​처리하십시오.



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
@Peter 더 간단한 용어로 설명하고 싶습니까? 나는 루비를 배우고 있는데 Maha의 대답은 나에게 완벽 해 보인다.
Marlen TB

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.