演算子メソッド
CoddyのRubyジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 38/57。
Rubyのほとんどの演算子はメソッドです。a + bはa.+(b)を呼び出すため、クラスでは他のメソッドと同じように+を定義します。値オブジェクトに対する算術演算は新しいオブジェクトを返し、両方のオペランドは変更しません。
class Vector
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def +(other)
Vector.new(x + other.x, y + other.y)
end
def to_s
"(#{x}, #{y})"
end
end
a = Vector.new(1, 2)
b = Vector.new(3, 4)
puts a + b
puts a出力:
(4, 6)
(1, 2)右オペランドには、スケーリングに使う数値など、別の種類の値を指定することもできます。単項マイナスは -@ メソッドです。
class Vector
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def -(other)
Vector.new(x - other.x, y - other.y)
end
def *(factor)
Vector.new(x * factor, y * factor)
end
def -@
Vector.new(-x, -y)
end
def to_s
"(#{x}, #{y})"
end
end
v = Vector.new(3, 4)
puts v * 2
puts v - Vector.new(1, 1)
puts(-v)出力:
(6, 8)
(2, 3)
(-3, -4)+ が存在すれば、+= も機能します。これは、a += b が a = a + b を意味するためです。sum も、クラスのインスタンスを開始値として渡すと機能します。
class Money
attr_reader :cents
def initialize(cents)
@cents = cents
end
def +(other)
Money.new(cents + other.cents)
end
def to_s
format("$%.2f", cents / 100.0)
end
end
total = Money.new(0)
total += Money.new(250)
total += Money.new(199)
puts total
puts [Money.new(100), Money.new(5)].sum(Money.new(0))出力:
$4.49
$1.05<=> も演算子です。Comparable と組み合わせることで、Money オブジェクトを比較およびソートでき、数値の場合と同様に、演算子は不一致のオペランドに対して例外を発生させて処理を拒否できます。
class Money
include Comparable
attr_reader :cents, :currency
def initialize(cents, currency)
@cents = cents
@currency = currency
end
def +(other)
raise ArgumentError, "cannot add #{other.currency} to #{currency}" unless other.currency == currency
Money.new(cents + other.cents, currency)
end
def <=>(other)
cents <=> other.cents
end
end
puts Money.new(500, "EUR") > Money.new(300, "EUR")
begin
Money.new(1, "EUR") + Money.new(1, "USD")
rescue ArgumentError => e
puts e.message
end出力:
true
cannot add USD to EURチャレンジ
簡単クラス Vectorを完成させてください。2つのベクトルに対する+と-、ベクトルと数値に対する*、単項マイナス-@、両方の座標を比較する==、そして(4, 6)を返すto_sを定義してください。lengthはMath.sqrtを使ってベクトルの長さを返します。
提供されたコードは、1,2 + 3,4、1,2 - 3,4、1,2 * 3、neg 1,2、1,2 == 1,2という式を読み取ります。それぞれの結果を出力し、ベクトルの結果については小数点以下2桁でlength 7.21も出力します。
コードはvector.rbに記述してください。main.rbには提供された入出力コードが含まれており、編集できません。
自分で試してみよう
require_relative 'vector'
# 提供された入出力コード: そのままにしておく
input = []
while (line = gets)
input << line.chomp
end
def vec(text)
Vector.new(*text.split(",").map(&:to_i))
end
input.each do |line|
parts = line.split
result = if parts[0] == "neg" then -vec(parts[1])
else
a = vec(parts[0])
case parts[1]
when "+" then a + vec(parts[2])
when "-" then a - vec(parts[2])
when "*" then a * parts[2].to_i
else a == vec(parts[2])
end
end
puts result
puts format("length %.2f", result.length) if result.is_a?(Vector)
end
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rubyオンラインコンパイラ