跳至內容

多載

我們可以定義一個 become_older 方法,它接受一個數字來表示要成長的年數。

class Person
  getter :age

  def initialize(@name : String, @age : Int = 0)
  end

  def become_older
    @age += 1
  end

  def become_older(years)
    @age += years
  end
end

john = Person.new "John"
john.age # => 0

john.become_older
john.age # => 1

john.become_older 5
john.age # => 6

也就是說,您可以擁有相同名稱但參數數量不同的方法,它們會被視為獨立的方法。這稱為方法多載

方法會根據以下幾個標準進行多載:

  • 參數的數量
  • 套用至參數的類型限制
  • 必要的具名參數的名稱
  • 方法是否接受區塊

例如,我們可以定義四個不同的 become_older 方法

class Person
  @age = 0

  # Increases age by one
  def become_older
    @age += 1
  end

  # Increases age by the given number of years
  def become_older(years : Int32)
    @age += years
  end

  # Increases age by the given number of years, as a String
  def become_older(years : String)
    @age += years.to_i
  end

  # Yields the current age of this person and increases
  # its age by the value returned by the block
  def become_older(&)
    @age += yield @age
  end
end

person = Person.new "John"

person.become_older
person.age # => 1

person.become_older 5
person.age # => 6

person.become_older "12"
person.age # => 18

person.become_older do |current_age|
  current_age < 20 ? 10 : 30
end
person.age # => 28

請注意,在會 yield 的方法的情況下,編譯器會判斷出來,因為有 yield 表達式。為了更明確地表示,您可以在最後新增一個虛擬的 &block 參數

class Person
  @age = 0

  def become_older(&block)
    @age += yield @age
  end
end

在產生的文件中,無論您是否編寫,都會永遠顯示虛擬的 &block 方法。

在參數數量相同的情況下,編譯器會嘗試對它們進行排序,將限制較少的方法放在最後。

class Person
  @age = 0

  # First, this method is defined
  def become_older(age)
    @age += age
  end

  # Since "String" is more restrictive than no restriction
  # at all, the compiler puts this method before the previous
  # one when considering which overload matches.
  def become_older(age : String)
    @age += age.to_i
  end
end

person = Person.new "John"

# Invokes the first definition
person.become_older 20

# Invokes the second definition
person.become_older "12"

但是,編譯器並非總是能夠判斷出順序,因為並非總是存在全序關係,因此最好始終將限制較少的方法放在最後。