Ruby: Gọi phương thức lớp từ ví dụ


347

Trong Ruby, làm thế nào để bạn gọi một phương thức lớp từ một trong các thể hiện của lớp đó? Nói tôi có

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

dòng Truck.default_makelấy mặc định. Nhưng có cách nào để nói điều này mà không đề cập đến Truck? Có vẻ như nên có.

Câu trả lời:


563

Thay vì đề cập đến tên theo nghĩa đen của lớp, bên trong một phương thức cá thể bạn chỉ có thể gọi 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

Đầu ra:

Phương pháp lớp học: Foo
Phương pháp sơ thẩm: Foo

7
tôi muốn thấy một số phím tắt trong ruby ​​để gọi một phương thức lớp từ một thể hiện. tức là:> some_group_method thay vì self. class.some_group_method
phoet

7
trong khi đây là câu trả lời đúng, thật đáng tiếc khi "self. class" lại gõ nhiều hơn và dễ đọc hơn tên lớp "Truck". ồ ....
Matt Connolly

22
@MattConnolly, nó tương đối, nếu tên lớp của bạn SalesforceSyncJobngắn hơn;)
thu hút

29
@MattConnolly, cũng sử dụng self.classloại bỏ nhu cầu tìm kiếm / thay thế nếu bạn đổi tên lớp.
Gus Shortz

8
@GusShortz đúng. Ngoài ra, self. Class hoạt động tốt hơn nếu có một lớp con.
Matt Connolly

183

Sử dụng self.class.blahKHÔNG giống như sử dụng ClassName.blahkhi nói đến thừa kế.

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
Đây dường như là một câu trả lời cho câu trả lời được chấp nhận hơn là một câu trả lời cho câu hỏi.
zhon

16
@zohn - đúng, nhưng đây vẫn là bối cảnh hữu ích khi xem xét sử dụng cái gì.
Matt Sanders

1
@MattSanders chỉ cần sử dụng một nhận xét trong những trường hợp đó.
nandilugio

1
@hlcs self.classlà chính xác để bảo tồn thừa kế. mặc dù make1()được định nghĩa trong Truck, nó tham chiếu BigTruckphương thức lớp.
Kaiser Shahid

Class_name.method_name hoạt động hoàn hảo
Houda M

14

Để truy cập một phương thức lớp bên trong một phương thức cá thể, hãy làm như sau:

self.class.default_make

Đây là một giải pháp thay thế cho vấn đề của bạn:

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

Bây giờ hãy sử dụng lớp của chúng tôi:

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

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

thực hiện không nên là một phương thức ví dụ. đó là một loại nhà máy hơn, nên gắn kết với lớp hơn là một ví dụ
phoet

6
@phoet Từ tạo ra biểu thị việc tạo ra một chiếc xe hơi (như trong Toyota, BMW, v.v.) englishforums.com/English/AMakeOfCar/crcjb/post.htmlm . Danh pháp dựa trên yêu cầu của người dùng
Harish Shetty

8

Nếu bạn có quyền truy cập vào phương thức ủy nhiệm, bạn có thể làm điều này:

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

Ngoài ra, và có thể sạch hơn nếu bạn có nhiều hơn một phương thức hoặc hai bạn muốn ủy quyền cho lớp & thể hiện:

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

Một lời cảnh báo:

Đừng chỉ ngẫu nhiên delegatemọi thứ không thay đổi trạng thái thành lớp và cá thể vì bạn sẽ bắt đầu gặp phải các vấn đề xung đột tên lạ. Làm điều này một cách tiết kiệm và chỉ sau khi bạn kiểm tra không có gì khác bị nghiền nát.



5

Bạn đang làm nó đúng cách. Các phương thức lớp (tương tự như các phương thức 'tĩnh' trong C ++ hoặc Java) không phải là một phần của thể hiện, vì vậy chúng phải được tham chiếu trực tiếp.

Trên lưu ý đó, trong ví dụ của bạn, bạn sẽ được phục vụ tốt hơn khi biến 'default_make' thành một phương thức thông thường:

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

Các phương thức lớp hữu ích hơn cho các hàm kiểu tiện ích sử dụng lớp. Ví dụ:

#!/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
Tôi không đồng ý rằng đó default_makelà một phương pháp ví dụ. Ngay cả khi các ví dụ này đơn giản hơn, thì đó không phải là ngữ nghĩa đúng - mặc định là sản phẩm của lớp, không phải các đối tượng thuộc về lớp.
Peter

1
@Peter bạn có quan tâm để giải thích điều đó bằng những thuật ngữ đơn giản hơn không? Tôi chỉ đang học câu trả lời của Ruby và Maha có vẻ hoàn hảo với tôi.
Marlen TB

1
@ MarlenT.B. nhìn lại tôi không chắc có quá nhiều thứ phải học ở đây - tôi chỉ tranh luận về nơi tốt nhất để đặt phương pháp là gì, và tôi không mua lập luận của riêng mình mạnh mẽ nữa! :)
Peter

2
Tôi cũng không đồng ý. Cho dù một cái gì đó là một phương thức lớp không liên quan gì đến "tiện ích". Đó là về việc phương thức này áp dụng một cách khái niệm cho lớp hay một đối tượng của lớp đó. Ví dụ: mỗi xe tải có một số sê-ri khác nhau, vì vậy serial_number là một phương thức thể hiện (với biến đối tượng tương ứng). Trên VEHICLE_TYPE khác (trong đó lợi nhuận "xe tải") nên có một phương pháp học bởi vì đó là một tài sản của tất cả các xe tải, không phải là một chiếc xe tải đặc biệt
Vish

3

Một lần nữa:

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

Đây là một cách tiếp cận về cách bạn có thể thực hiện một _classphương pháp hoạt động như self.classtrong tình huống này. Lưu ý: Không sử dụng mã này trong mã sản xuất, đây là vì lợi ích :)

Từ: Bạn có thể mã eval trong ngữ cảnh của một người gọi trong 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

Có lẽ câu trả lời đúng là gửi một bản vá cho Ruby :)


-6

Tương tự câu hỏi của bạn, bạn có thể sử dụng:

class Truck
  def default_make
    # Do something
  end

  def initialize
    super
    self.default_make
  end
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.