#author("2016-05-25T02:52:15+00:00","default:nitta","nitta")
#author("2016-05-25T03:02:12+00:00","default:nitta","nitta")
[[Swift]]

*Swift/演算子 [#mabb75af]

"." や "," は演算子ではない。
代入演算子は値を返さない。

優先度は0-255の整数で表わし、数値が大きいほど優先度が高い。
後置演算子と前置演算子には優先度の数値はない。
後置演算子、前置演算子、二項演算子の順に優先される。

C言語やObjective-Cの演算子とは優先順位が異なる(特にビット演算関係)ので注意すること。

LEFT:
|演算子 | 結合 | 優先 |
|p++ p-- a! a? a. | 左から右 | (!?.は演算子ではない)|
|++p --p +a -a ~a !a | 右から左 ||
|<< >> | x | 160 |
|* / % & &* | 左から右 | 150 |
|+ - &#124; &#94; &#38;+ &#38;-|左から右|140|
|.. < ...|x|135|
|is as as? as!|x|132|
|??|右から左|131|
|< <= > >= ~= == != === !==|x|130|
|&&|左から右|120|
|&#124;&#124;|左から右|110|
|条件 ? 式1 : 式2|右から左|100|
|= *= /= %= += -= <<= >>= &#38;= &#94;= &#124;= |右から左|90|

右から左 = op (op A), A op (B op C) ~
左から右 = (A op) op, (A op B) op C ~
x = A op B op C のように記述できない ~

**オーバーフロー演算子 [#t62af7b5]


Swiftでは通常の計算においてオーバーフローやアンダーフローが発生すると実行時エラーを発生してプログラムは停止する。
オーバーフローやアンダーフローが発生しても実行時エラーとして扱わないための演算子がオーバーフロー演算子(&+, &-, &*) である。
 var z : UInt 8 = 1
 z = z &- 2         // z == 255 になる。もしも z - 2を計算するとエラーになる。

**剰余演算子 [#l8e3353b]

実数値に対しても適用できる。
 c = sign(a) * ( |a| - ( floor( |a| / |b| ) * |b| ) )
c = a % b を計算した場合、cの符号はaと同じで、bは正負どちらでもcは変らない。
 11.0 % 2.5 = 1.0
 11.0 % -2.5 = 1.0
 -11.0 % 2.5 = -1.0
 -11.0 % -2.5 = -1.0

**ビット演算子と論理演算子 [#d2b58092]
 func odd(i:Int) -> Bool { print(i); return i&1 == 1 }
 var b = true
 var c1 = b || odd(1)    // oddは実行しない。c1はtrue
 var c2 = !b && odd(1)    // oddは実行しない。c1はfalse

**nil合体演算子 [#c9c921c7]
 opv ?? S
は
 (opv != nil) ? opv! : S
と同じ意味である。

**参照型の値であるクラスのインスタンスが同一のものか調べる [#bc98a01e]
 ===
 !==
 

*演算子の定義 [#sa8a4a8b]

-まったく新しい演算子を定義する。
-すでに使われている演算子に別な使い方を定義する。
--これまで単項演算子として使われていた演算子に二項演算子の定義を加える。または、その逆。
---これまでとは違うデータ型に対して適用可能にする。

演算子として独自定義ができないもの
| = | 代入演算子以外に型パラメータの定義などにも使われている|
| -> | 関数型の宣言で利用 |
| . | 名前の修飾で利用 |
| // | 行単位のコメント |
| /* | コメント箇所の開始 |
| */ | コメント箇所の終了 |
| ? | 三項演算子、オプショナルチェーンなどで利用 |
| & | 前置演算子としては使えない。inoutパラメータの指定に利用 |
| < | 前置演算子としては使えない。<T>のような型パラメータの指定に利用 |
| > | 後置演算子としては使えない。<T>のような型パラメータの指定に利用 |
| ! | 後置演算子としては使えない。unwrap指示子 |


演算子宣言の概要
 二項演算子
 infix operator 演算子 {
   precedence 数字
   associativity 規則
 }
 前置演算子
 prefix operator 演算子 { }
 後置演算子
 postfix operator 演算子 { }

優先度はデフォルト値では100である。
結合規則は left, right, none のいずれかを指定でき、デフォルト値はnone。
一度何かの目的のために宣言された演算子は、別なデータ型向けに定義(オーバーロード)
することはできるが、優先度や結合規則は変えられない。
演算子は複数個の文字の組み合わせで構成でき、先頭と2文字目に使える文字はSwiftの仕様として決められている。
ASCII文字の一部の記号の他に、Unicodeの数学用記号(U+2190 - U+23FF)などが利用できる。

二項演算子の定義例

 infix operator ~ {    // 二項演算子として宣言する
   precednece 20       // 他の演算子より低い優先度
   associativity none  // 結合規則は none
 }
 func ~ (n:Int, w:Int) -> String {
   var str = String(n)
   let pad = w - str.characters.count    // 左に詰める空白の個数
   if pad > 0 {
     str = String(count:pad, repeatedValue:Character(" ")) + str
   }
   return str
 }
使い方は次の通り。
 print(x+f(2) ~ 8)    // x+f(2) の演算結果を8桁の文字列にして表示する。

 for var wid = 2; wid <= 6; wid += 2 {
   for i in 1...5 {
     print(i+7 ~ wid, terminator:"")  // 演算子 ~ の優先度は + よりも低い
   }
   print("")
 }

単項演算子(後置演算子)の定義例
 postfix operator % {}    // 後置演算子として宣言
 postfix func % (n:Int) -> Double {   // postfixの指定は必須
   return 0.01 * Double(n)
 }
 postfix func % (r:Double) -> Double {
   return 0.01 * r
 }

「19,800円の品物を85%で販売し、消費税8%がついたらいくらになるか」を計算する。
 var price: Double = 19.800
 print(price * 85% * 1.08%)    // 18176.4と表示される。

引数の変数の値を変更するには、演算子の関数定義において inout 引数を使う。
ただし、通常の関数呼び出しとは異なり、呼び出す側で & を記述する必要はない。
 infix operator >? {    // 二項演算子として宣言する
   precedence 90        // 代入演算子と同じ優先度
   associativity none   // 結合規則は none
 }
 func >? (intout lhs:Double, rhs:Double) {  // lhs: Left Hand Side 左辺
   if lhs < rhs { lhs = rhs }               // rhs: Right Hand Side 右辺
 }

 var a = 1.22
 for x in [ 0.9, 1.25, -1.0, 2.0, 0.86 ] {
   a >? x   // 演算氏を使う。&の指定は不要
 }
 print(a)    // 最大値の 2.0 が表示される。

構造体に対する演算子の定義
 struct Time : CustomStringConvertible {
   let hour, min : Int    // 定数で時刻を保持。memberwise initializerを使う。
   func add(min:Int) -> Time {
     var m = self.min + min
     var h = self.hour
     if m >= 60 {
       h = (h + m / 60) % 24
       m %= 60
     }
     return %= 60
   }
   var description : String {
     let h = hour < 10 ? " \(hour)" : "\(hour)"
     let m = min < 10 ? "0\(min)" : "\(min)"
     return h + ":" + m
   }
 }

 func + (tm:Time, inc:Int) -> Time {   // 指定した時間(分)を加算する
   return tm.add(inc)                  // 新しいインスタンスを返す
 }
 func - (t1:Time, t2:Time) -> Int {    // 2つの時刻の差を計算する
   var m1 = t1.hour * 60 + t1.min      // 分単位に直す
   let m2 = t2.hour * 60 + t2.min
   if (m1 < m2) { m1 += 24 * 60 }      // 日付をまたぐ場合
   return m1 - m2
 }
 prefix func ++ (inout tm:Time) -> Time {  // inout に注意
   tm = tm.add(1)                          // 加算の結果を引数に代入する
   return tm                               // 新しいインスタンスを返す
 }
 postfix func ++ (inout tm:Time) -> Time { // inoutに注意
   let newone = tm
   tm = tm.add(1)
   return newone
 }
 func += (inout tm:Time, inc:Int) {
   tm = tm.add(inc)
 }


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS