Ruby:从实例调用类方法

Ruby: Calling class method from instance

在Ruby中,如何从类的一个实例调用类方法?说我有

1
2
3
4
5
6
7
8
9
10
11
12
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检索默认值。但是,有没有一种方法可以这样说,而不提及以东十一〔一〕?似乎应该有。


在实例方法中,您可以调用self.class.whatever,而不是引用类的文字名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

输出:

1
2
Class method: Foo
Instance method: Foo


在继承问题上,使用self.class.blah与使用ClassName.blah不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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"


要访问实例方法内的类方法,请执行以下操作:

1
self.class.default_make

以下是解决您问题的另一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

现在让我们使用我们的类:

1
2
3
4
5
6
7
8
9
10
11
t = Truck.new("Honda", 2000)
t.make
# =>"Honda"
t.year
# =>"2000"

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


1
self.class.default_make

如果您有权访问委托方法,则可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
[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
2
3
4
5
6
7
8
9
10
11
12
13
14
[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"

注意事项:

不要只是随机地删除cx1(3)所有不改变类和实例状态的内容,因为您将开始遇到奇怪的名称冲突问题。谨慎地做这件事,只有在你检查过之后,其他的东西才被压扁。


你做得对。类方法(类似于C++或Java中的"static"方法)不是实例的一部分,因此它们必须直接引用。

注意,在您的示例中,最好将"默认制作"作为常规方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/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()

类方法对于使用类的实用程序类型函数更有用。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 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的补丁:)


与您的问题类似,您可以使用:

1
2
3
4
5
6
7
8
9
10
class Truck
  def default_make
    # Do something
  end

  def initialize
    super
    self.default_make
  end
end