演算子式

[edit]


1+2*3/4

プログラミングの利便のために一部のメソッド呼び出しと制御構造は演算子形式をとります。Rubyには以下にあげる演算子があります。

高い   ::
       []
       +(単項)  !  ~
       **
       -(単項)
       *  /  %
       +  -
       << >>
       &
       |  ^
       > >=  < <=
       <=> ==  === !=  =~  !~
       &&
       ||
       ..  ...
       ?:(条件演算子)
       =(+=, -= ... )
       not
低い   and or

左の「高い」「低い」は演算子の優先順位です。例えば「&&」は「||」より優先順位が高いので、以下のように解釈されます。


a && b || c   #=> (a && b) || c
a || b && c   #=>  a || (b && c)

ほとんどの演算子は特別な形式のメソッド呼び出しですが、一部のものは言語に組み込みで、再定義できません。

再定義できる演算子(メソッド)

+@, -@ は単項演算子 +, - を表しメソッド定義などではこの記法を利用します。

    |  ^  &  <=>  ==  ===  =~  >   >=  <   <=   <<  >>
    +  -  *  /    %   **   ~   +@  -@  []  []=  ` ! != !~

これらの演算子式の定義方法についてはクラス/メソッドの定義/演算子式の定義を参照してください。

再定義できない演算子(制御構造)

演算子の組合せである自己代入演算子は再定義できません。

    =  ?:  ..  ...  not  &&  and  ||  or  ::

代入



foo = bar
foo[0] = bar
foo.bar = baz

文法:

変数 '=' 式
定数 '=' 式
式`['expr..`]' '=' 式
式`.'識別子 '=' 式

代入式は変数などに値を設定するために用いられます。代入はローカル変数や定数の宣言としても用いられます。代入式の左辺は以下のいずれかでなければなりません。

変数
            変数 `=' 式

左辺値が変数の場合、式を評価した値が変数に代入されます。

配列参照
            式1`[' 式2 ... `]' `=' 式n

式1を評価して得られるオブジェクトに対しての、式 2 から式 n までを引数とする []= メソッド呼び出しに変換されます。



class C
  def initialize
    @ary = [0,1,2,3,4,5,6,7]
  end
  def [](i)
    @ary[i * 2]
  end
  def []=( i, v )
    @ary[i * 2] = v
  end
end
c = C.new
p c[3]      # c.[]( 3 )  に変換され、その結果は 6
p c[3] = 1  # c.[]=(3,1) に変換され、その結果は 1
属性参照
            式1 `.' 識別子 `=' 式2

式 1 を評価して得られるオブジェクトに対して、識別子= というメソッドを、式 2 を引数にして呼び出します。



class C
  def foo
    @foo
  end
  def foo=( v )
    @foo = v
  end
end
c = C.new
c.foo = 5   # c.foo=( 5 ) のように変換される
p c.foo     # => 5

属性は Module#attr を使って同じように定義できます。



class C
  attr :foo, true
end
c = C.new
c.foo = 5   # c.foo=( 5 ) のように変換される
p c.foo     # => 5

自己代入



foo += 12       # foo = foo + 12
a ||= 1         # a が偽か未定義ならば1を代入。初期化時のイディオムの一種。

文法:

式1 op= 式2     # 式1は通常の代入の左辺のいずれか

op は以下のいずれかです。演算子と=の間にスペースを空けてはいけません。

+, -, *, /, %, **, &, |, ^, <<, >>, &&, ||

この形式の代入は

式1 = 式1 op 式2

と評価されます。ただし、op が &&, || の場合には、

式1 op (式1 = 式2)

と評価されます。この違いは属性参照のときに


obj.foo ||= true

が、


obj.foo = obj.foo || true

でなく


obj.foo || (obj.foo = true)

と呼ばれることを示します。(obj.foo= は obj.foo の結果によって呼ばれないかも知れません)

多重代入



foo, bar, baz = 1, 2, 3
foo, = list()
foo, *rest = list2()

文法:

式 [`,' [式 `,' ... ] [`*' [式]]] = 式 [, 式 ... ][`*' 式]
`*' [式] = 式 [, 式 ... ][`*' 式]

多重代入は複数の式または配列から同時に代入を行います。左辺の各式はそれぞれ代入可能でなければなりません。右辺の式が一つしか与えられなかった場合、式を評価した値は配列に変換されて、各要素が左辺のそれぞれの式に代入されます。左辺の要素の数よりも配列の要素の数の方が多い場合には、余った要素は無視されます。配列の要素が足りない場合には対応する要素の無い左辺には nil が代入されます。

左辺の最後の式の直前に * がついていると、対応する左辺のない余った要素が配列として代入されます。余った要素が無い時には空の配列が代入されます。



foo, bar = [1, 2]       # foo = 1; bar = 2
foo, bar = 1, 2         # foo = 1; bar = 2
foo, bar = 1            # foo = 1; bar = nil

foo, bar, baz = 1, 2    # foo = 1; bar = 2; baz = nil
foo, bar = 1, 2, 3      # foo = 1; bar = 2
foo      = 1, 2, 3      # foo = [1, 2, 3]
*foo     = 1, 2, 3      # foo = [1, 2, 3]
foo,*bar = 1, 2, 3      # foo = 1; bar = [2, 3]

多重代入は括弧により、ネストした配列の要素を代入することもできます。


(foo, bar), baz = [1, 2], 3       # foo = 1; bar = 2; baz = 3

特殊な形式の代入式も多重代入にすることができます。


class C
  def foo=( v )
    @foo = v
  end
  def []=(i,v)
    @bar = ["a", "b", "c"]
    @bar[i] = v
  end
end

obj = C.new
obj.foo, obj[2] = 1, 2     # @foo = 1; @bar = ["a", "b", 2]

左辺が `,' で終る場合や、`*' の直後の式を省略した場合にも余った要素は無視されます。



foo,*    = 1, 2, 3      # foo = 1
foo,     = 1, 2, 3      # foo = 1
*        = 1, 2, 3

特に最後の単体の `*' はメソッド呼び出しにおいて引数を完全に無視したいときに使用できます。(メソッド呼び出しの引数の受け渡しは多重代入とほぼ同じルールが適用されます)



def foo(*)
end
foo(1,2,3)

多重代入の値は配列に変換された右辺です。

範囲式



1 .. 20
/first/  ...  /second/
(1..)

文法:

式1 `..' 式2
式1 ` ... ' 式2
式1 `..'
式1 ` ... '

条件式以外の場所では式1から式2までの範囲オブジェクトを返します。範囲オブジェクトはRangeクラスのインスタンスです。 ... で生成された範囲オブジェクトは終端を含みません。

終端を省略した Range は終端のない範囲を表現できます。 (1..) は (1..nil) の構文糖です。 (1...) とは exclude_end が違うため、オブジェクトとしては等しくありませんが、ary[1..] と ary[1...] のように通常の使い方では同じように扱えます。

when 1.. のように書くと、行継続とみなされるため、終端なし Range にするにはかっこが必要になることがあるので、注意してください。

条件式としての範囲式

条件式として範囲式が用いられた場合には、状態を持つ sed や awk 由来の特殊な条件式として振る舞います。フリップフロップ (flip-flop) とも呼ばれます。

「..」の場合:

  1. 初期状態では式1だけを評価し、式1が真を返すまでは false を返します。
  2. 式1が真を返すと true を返します。式2が真なら初期状態に戻ります。
  3. この後は式2だけを評価し、式2が真を返すまで true を返します。
  4. 式2が真を返すと true を返したあと、初期状態に戻ります。

「...」の場合:

  1. 初期状態では式1だけを評価し、式1が真を返すまでは false を返します。
  2. 式1が真を返すと true を返します。
  3. この後は式2だけを評価し、式2が真を返すまで true を返します。
  4. 式2が真を返すと true を返したあと、初期状態に戻ります。


# よくある使いかた

5.times{|n|
  if (n==2)..(n==3)
    p n
  end
}
#=> 2
#   3

5.times{|n|
  if (n==2)...(n==3)
    p n
  end
}
#=> 2
#   3

# 「..」と「...」の違いを示すためだけの例

5.times{|n|
  if (n==2)..(n==2)
    p n
  end
}
#=> 2

5.times{|n|
  if (n==2)...(n==2)
    p n
  end
}
#=> 2
#   3
#   4

and



test && set
test and set

文法:

式 `&&' 式
式 `and' 式

左辺を評価し、結果が偽であった場合はその値(つまり nil か false) を返します。左辺の評価結果が真であった場合には右辺を評価しその結果を返します。 and は同じ働きをする優先順位の低い演算子です。


p(nil && false) # => nil
p(false && nil) # => false
p(1 && 2) # => 2

and を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。


p(true && false)    #=> false
p((true and false)) #=> false

or



demo || die
demo or die

文法:

式 `||' 式
式 or 式

左辺を評価し、結果が真であった場合にはその値を返します。左辺の評価結果が偽であった場合には右辺を評価しその評価結果を返します。 or は同じ働きをする優先順位の低い演算子です。


p(1 || 2) # => 1
p(nil || false) # => false
p(false || nil) # => nil

or を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。


p(false || true)    #=> true
p((false or true)) #=> true

not



! me
not me
i != you

文法:

`!' 式
not 式

式の値が真である時偽を、偽である時真を返します。

式 `!=' 式

!(式 == 式)と同じ。

式 `!~' 式

!(式 =~ 式)と同じ。

not を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。


p(! false)      #=> true
p((not false))  #=> true

条件演算子



obj == 1 ? foo : bar

文法:

式1 ? 式2 : 式3

式1の結果によって式2または式3を返します。

if 式1 then 式2 else 式3 end

とまったく同じです。