【Ruby】演算子
- 作者: 高橋征義,後藤裕蔵,まつもとゆきひろ
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2013/06/04
- メディア: 単行本
- この商品を含むブログ (22件) を見る
今回は第9章「演算子」
代入演算子
二項演算子と代入を組み合わせた演算子のこと。
+= や *= などを指す。
変数だけでなく、メソッドを経由したオブジェクトの操作にも使うこともできる。
# 同じ意味を持つ $stdin.lineno += 1 $stdin.lineno = $stdin.lineno + 1
これらの式は「$stdin.lineno」と「$stdin.lineno=」という2つのメソッドを呼び出していることに注意。
論理演算子の応用
論理演算子は3つの特徴がある。
- 左側の式から順に評価される
- 論理式の真偽が決定すると残りの式は評価されない
- 最後に評価された式の値が論理式全体の値となる
まず、|| について。
条件1 || 条件2
この論理式では必ず条件1、条件2の順に真偽が判定される。ここで条件1の結果が真の時、全体が真となるのは明らかなので、無駄な条件(条件2)の判定は行わないようになっている。逆に、条件1が偽でなければ条件2は評価されない。
条件1 || 条件2 || 条件3
このような場合でも同様である。条件1と条件2の両方が偽にならなければ、条件3の判定は行われない。
var || "Ruby"
この式では、変数 var の真偽が判断され、nil か false の場合にのみ文字列 "Ruby" の真偽が判断される。論理式の戻り値は最後に評価された式の戻り値に一致するので、この式全体の戻り値は、
となる。
次は && について。
基本的なルールは || と同じである。
条件1 && 条件2
|| の時とは逆に、条件1が真の場合にのみ条件2が評価される。
これらの性質を利用した応用する。
name = "Ruby" # name にデフォルト値を設定する if var # var が nil または false でなければ name = var # name に var を代入する end
この4行を1行にまとめるとこうなる。
name = var || "Ruby"
次は変数に配列の先頭要素を代入する場合。
item = nil # item に初期値を設定 if ary # ary が nil または false でなければ item = ary[0] # ary[0] に item を代入 end
ary が nil でないことを確認してから変数 item への代入を行っている。
これも1行にまとめることができる。
item = nil && ary[0]
# || の代入演算子 var = var || 1 var ||= 1 # 同じ意味
var が nil か false の場合に限り1を代入する、という意味になる。
範囲演算子
値の範囲を表すオブジェクト。
# 1から10までを表す範囲オブジェクト Range.new(1, 10) 1..10 # 省略形
範囲演算子には「..」と「...」の2種類がある。
x ... y の場合、値の範囲は x から y の1つ手前までである。
p (5..10).to_a #=> [5, 6, 7, 8, 9, 10] p (5...10).to_a #=> [5, 6, 7, 8, 9] p ("a".."e").to_a #=> ["a", "b", "c", "d", "e"] p ("a"..."e").to_a #=> ["a", "b", "c", "d"]
Range オブジェクトの内部では succ メソッドを使っている。
val = "a" p val #=> "a" val = val.succ p val #=> "b" val = val.succ p val #=> "c"
演算子の優先順位
演算子には優先順位が設けられている。
優先度 高
:: [] +(単項演算子) ! ~ ** -(単項演算子) * / % + - << >> & | \ > >= < <= <=> == === != =~ !~ && || ?:(条件演算子) .. ... = (+= -= *= /= など含む) not and or
優先度 低
優先順位とは違う順番で計算したいときは、() で囲むことでより内側の () の中から順に計算される。
演算子を定義する
Ruby の演算子の多くはインスタンスメソッドとして実装されているため、一部を除いてユーザが新たに定義、再定義をして意味を変えることが出来る。
・再定義できない演算子
:: && || .. ... ?: not = and or
二項演算子
二項演算子を定義するには演算子をメソッド名としてメソッドを定義する。演算子の左の項がレシーバ、右側の項がメソッドの引数として渡される。
class Point attr_reader :x, :y def initialize(x=0, y=0) @x, @y = x, y end def inspect # 表示用 "(#{x}, #{y})" end def +(other) # x,yのそれぞれを足す self.class.new(x + other.x, y + other.y) end def -(other) # x,yのそれぞれを引く self.class.new(x - other.x, y - other.y) end end point0 = Point.new(3, 6) point1 = Point.new(1, 8) p point0 #=> (3, 6) p point1 #=> (1, 8) p point0 + point1 #=> (4, 14) p point0 - point1 #=> (2, -2)
二項演算子を定義するときは引数名に「other」がよく用いられる。
なお、self.class.new を Point.new メソッドを使うようにすることもできる。
def +(other) Point.new(x + other.x, y + other.y) end
単項演算子
定義可能な単項演算子は「+, -, ~, !」の4つ。
それぞれ「+@, -@」といった名前で定義できる。
class Point ... def +@ # 自分の複製を返す dup end def -@ self.class.new(-x, -y) # x,yのそれぞれの正負を逆にする end def ~@ self.class.new(-y, x) # 90度回転させた座標を返す end end point = Point.new(3, 6) p +point #=> (3, 6) p -point #=> (-3, -6) p ~point #=> (-6, 3)
添字メソッド
配列やハッシュで用いられる obj[i] と obj[i]=x のことである。それぞれ [ ] と [ ]= という名前で定義できる。
class Point attr_accessor :x, :y def initialize(x=0, y=0) @x, @y = x, y end def [](index) case index when 0 x when 1 y else raise ArgumentError, "out of range '#{index}'" end end def []=(index,val) case index when 0 self.x = val when 1 self.y = val else raise ArgumentError, "out of range'#{index}'" end end end point = Point.new(3, 6) p point[0] #=> 3 p point[1] = 2 #=> 2 p point[1] #=> 2 p point[2] #=> Error (ArgumentError)
引数 index が配列でいうところの添字である。今回の場合は、2以上の値をインデックスとして指定した場合に引数に誤りがあることを表す例外を上げている。