Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Ruby辞典

  1. トップページ
  2. Ruby辞典
  3. Comparable / <=> / ==

Comparable / <=> / ==

『Comparable』モジュールと宇宙船演算子『<=>』を使って、独自クラスに大小比較・並べ替えの機能を追加する方法です。

構文
class クラス名
  include Comparable  # Comparable モジュールをインクルードします。

  # <=> 演算子を定義します(唯一の必須実装)。
  def <=>(other)
    # 自分が小さいとき: 負の数を返します。
    # 等しいとき:       0 を返します。
    # 自分が大きいとき: 正の数を返します。
    # 比較不能なとき:   nil を返します。
    自分の比較値 <=> other.比較値
  end
end

# <=> を定義すると以下のメソッドが自動的に使えるようになります。
オブジェクト <  other   # より小さい
オブジェクト <= other   # 以下
オブジェクト >  other   # より大きい
オブジェクト >= other   # 以上
オブジェクト.between?(min, max)  # 範囲内判定
オブジェクト.clamp(min, max)     # 範囲内に収める(Ruby 2.4+)
配列.sort  # Comparable を実装したオブジェクトの配列を並べ替えられます。
メソッド一覧
演算子 / メソッド概要
<=> (other)宇宙船演算子。自分がotherより小さければ負、等しければ0、大きければ正の整数を返します。
<『<=>』の結果が負のとき『true』を返します。Comparableが自動生成します。
<=『<=>』の結果が負またはゼロのとき『true』を返します。
>『<=>』の結果が正のとき『true』を返します。
>=『<=>』の結果が正またはゼロのとき『true』を返します。
between?(min, max)min以上max以下なら『true』を返します。
clamp(min, max)min〜maxの範囲に収めた値を返します。
サンプルコード
# 温度クラスに Comparable を実装します。
class Temperature
  include Comparable

  attr_reader :degrees

  def initialize(degrees)
    @degrees = degrees
  end

  # <=> を定義します(これだけで比較演算子がすべて使えます)。
  def <=>(other)
    @degrees <=> other.degrees
  end

  def to_s
    "#{@degrees}°C"
  end
end

freezing  = Temperature.new(0)
body_temp = Temperature.new(36.5)
boiling   = Temperature.new(100)
fever     = Temperature.new(38.5)

# 比較演算子が使えます。
puts freezing < boiling    # true
puts boiling > body_temp   # true
puts freezing <= freezing  # true

# between? で範囲判定。
puts fever.between?(body_temp, boiling)  # true(平熱より高く沸点より低い)

# sort で並べ替えられます。
temperatures = [boiling, freezing, fever, body_temp]
puts temperatures.sort.map(&:to_s).inspect
# ["0°C", "36.5°C", "38.5°C", "100°C"]

# clamp で範囲内に収めます。
外気温 = Temperature.new(45)
適正範囲内 = 外気温.clamp(Temperature.new(10), Temperature.new(40))
puts 適正範囲内  # 40°C(最大値に収められます)
概要

『Comparable』モジュールを『include』し、『<=>』(宇宙船演算子)を1つ定義するだけで、6つの比較演算子(『<』『<=』『>』『>=』『between?』『clamp』)がすべて自動的に使えるようになります。これがRubyのモジュールとミックスインの典型的な活用例です。

『<=>』は比較不能な場合に『nil』を返す必要があります。例えば数値同士なら問題ありませんが、異なる型を比較する場合は型チェックを行い、比較できない場合は『nil』を返すように実装してください。

『<=>』で『nil』を返した場合、『sort』メソッドは『ArgumentError』を発生させます。ソートの対象となる可能性があるクラスでは、必ずすべての場合に整数または0を返すように実装してください。

モジュールとミックスインの仕組みは『module / include / extend』を、クラスの継承は『継承 / super』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。