Kotlin——初級篇(五):操作符與操作符過載一

Jetictors發表於2018-01-08

Kotlin——初級篇(五):操作符與操作符過載一

本篇文章為大家詳細的介紹Koltin特有的操作符過載。或許對於有程式設計經驗的朋友來說,操作符這個詞絕對不陌生,就算沒有任何編輯基礎的朋友,數學中的算數運算子也絕不陌生。例如(+、-、*、/、>、<、>=、<=)等。而算數運算子是程式語言中的一種操作符而已。就算你沒有任何基礎,也請你詳細的看完這篇文章,我相信你會很有收穫的。

目錄

Kotlin——初級篇(五):操作符與操作符過載一

一、約定

所謂預定:即指Kotlin允許我們為自己的型別提供預定義的一組操作符的實現。這些操作符具有固定的符號表示(如 +*)和固定的優先順序。為實現這樣的操作符,我們為相應的操作型別提供了一個固定名字的函式。這樣的技術,稱為約定

因為由類實現的介面集是固定的,而Kotlin不能為了實現其他介面而修改現有的類,因此一般通過擴充套件函式的機制來實現為現有的類增添新的約定方法,從而適應任何現有的Java類。

二、操作符與操作符過載

根據運算元據個數的不同,分為兩種操作型別:

  1. 一元操作:即指運算元只有一個的情況
  2. 二元操作:即指運算元存在二兩或多個的情況。特別說明:在存在多個運算元的情況下,會用複合運算或拆分為多個運算。

2.1、一元操作

一元操作:即指一個運算元的情況,

2.1.1、簡單的一元操作運算

這裡分為三種情況有三種一元操作:

  • + 表示為運算元實現一個正號的意思,其運算元為數值型
  • - 表示為運算元實現一個負號的意思,其運算元為數值型
  • ! 表示取反的意思,其運算元為boolean型別

提供一個表格直觀的展示:

操作符 過載
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()

例:

var a = 1
var b = -2
var c = true
var d = false

// 操作符實現
println("+a = ${+a}\t -a = ${-a}\t !c = ${!c}")
println("+b = ${+b}\t -b = ${-b}\t !d = ${!d}")

// 操作符過載實現
println("+a = ${a.unaryPlus()}\t -a = ${a.unaryMinus()}\t !c = ${c.not()}")
println("+b = ${b.unaryPlus()}\t -b = ${b.unaryMinus()}\t !d = ${d.not()}")
複製程式碼

輸出結果為:

+a = 1	 -a = -1	 !c = false
+b = -2	 -b = 2	 !d = true
+a = 1	 -a = -1	 !c = false
+b = -2	 -b = 2	 !d = true
複製程式碼
2.1.2、複雜的一元操作

複雜的一元操作符即指,對運算元進行自增、自減操作。和Java是一樣的

這裡主要有4種情況:

  • 字尾自增:表示為運算元進行自增操作,其運算元為數值型。例如:a++
  • 字尾自減:表示為運算元進行自減操作,其運算元為數值型。例如:a--
  • 字首自增:表示為運算元進行自增操作,其運算元為數值型。例如:++a
  • 字首自減:表示為運算元進行自增操作,其運算元為數值型。例如:--a

提供一個表格直觀的展示:

操作符 過載 表示
a++ a.inc() a = a.also{ a.inc() }
a-- a.dec() a = a.also{ a.dec() }
++a a.inc() a = a.inc().also{ a = it }
--a a.dec() a = a.dec().also{ a = it }

解釋:操作符++的過載為inc(),操作符--的過載為dec()。但是字首操作和字尾操作是有著明顯的區別的:

  • 字尾操作是第一次呼叫的時候不執行自身。在第二次開始進行自增或自減操作。
  • 字首操作是第一次呼叫的時候就執行自增或自減操作

例項:

var a = 10
var b = 10
var c = 10
var d = 10

// 操作符實現
println("a++ = ${a++} \t b-- = ${b--} \t ++c = ${++c} \t --d = ${--d}")

// 操作符過載方式實現,或許你看不明白上表中程式碼,不過這沒關係,你只要記住上面字首與字尾操作的區別就行
a.also { a.inc() }
b.also { b.dec() }
c.inc().also { c = it }
d.dec().also { d = it }
println("a = $a \t b = $b \t c = $c \t d = $d")
複製程式碼

輸出結果為:

a++ = 10 	 b-- = 10 	 ++c = 11 	 --d = 9
a = 10 	 b = 10 	 c = 11 	 d = 9
複製程式碼

2.2 二元操作

二元操作:即指運算元存在二兩或多個的情況。

2.2.1、簡單的二元操作

簡單的二元操作有:

  • a + b,表示兩個運算元相加,值得注意的是若某一個運算元為String型別時。其返回值為String型別,當且僅當兩個運算元都為數值型時,其返回值才會數值型。
  • a - b,表示兩個運算元相減,返回值為數值型
  • a * b,表示兩個運算元相乘,返回值為數值型
  • a / b,表示兩個運算元相除,返回值為數值型
  • a % b,表示兩個運算元相除後的餘數,官方稱之為,即a模以b 。返回值為Int
  • a .. b,表示範圍(區間),這裡不詳細說明,在下面一點的區間操作符一起講解。

這裡提供一個表格直觀的展示:

操作符 過載
a + b a.plus(b)
a - b a.minus(b)
a * b a.tiems(b)
a / b a.div(b)
a % b a.rem(b) 或 a.mod(b)
a .. b a.rangTo(b)

這裡值得注意的是:a % b的過載為a.rem()a.mod()。不過a.mod()Koltin1.0版本的過載方法,現在已經棄用了,Koltin1.1以及以上版本使用a.rem()過載方法

// 簡單的二元操作
val a = 10
val b = 2
val c = "2"
val d = "Kotlin"

// 操作符實現
println("a + d = " + a + d)
println("c + d = " + c + d)
println("a + b = ${a + b} \t a - b = ${a - b} \t a * b = ${a * b} \t a / b = ${a / b} \t a % b = ${a % b}")

// 操作符過載實現
// println("a + d = ${a + d}") 錯誤:字串模板限制只能為數值型
println("a + b = ${a.plus(b)} \t a - b = ${a.minus(b)} \t a * b = ${a.times(b)} \t a / b = ${a.div(b)} \t a % b = ${a.rem(b)}")
// println(a.plus(d))  錯誤:因為第一個運算元`a`限制了其plus()方法的引數,
// println(d.plus(a))  正確:因為plus()方法的引數為超(Any)型別
複製程式碼

輸出結果為:

a + d = 10Kotlin
c + d = 2Kotlin
a + b = 12 	 a - b = 8 	 a * b = 20 	 a / b = 5 	 a % b = 0
a + b = 12 	 a - b = 8 	 a * b = 20 	 a / b = 5 	 a % b = 0
複製程式碼

2.2.2、複合二元操作

複合的二元操作有:

  • a += b,表示第一個運算元的的值為第一個運算元加上第二個運算元,值得注意的是若某一個運算元為String型別時。其返回值為String型別,當且僅當兩個運算元都為數值型時,其返回值才會數值型。
  • a -= b,表示第一個運算元的的值為第一個運算元減去第二個運算元,返回值為數值型
  • a *= b,表示第一個運算元的的值為第一個運算元乘以第二個運算元,返回值為數值型
  • a /= b,表示第一個運算元的的值為第一個運算元除以第二個運算元,返回值為數值型
  • a %= b,表示第一個運算元的的值為第一個運算元模以第二個運算元 。返回值為Int

這裡提供一個表格直觀的展示:

操作符 表示 過載
a += b a = a + b a = a.plus(b)
a -= b a = a - b a = a.minus(b)
a *= b a = a * b a = a.tiems(b)
a /= b a = a / b a = a.div(b)
a %= b a = a % b a = a.rem(b)

例: 操作符實現

var b = 2
var a = 10
var c = "Kotlin"

// 主要演示字串的+=
c += a                          等價於  c = c.plus(a)
print("c = $c \t")

a += b                          等價於  a = a.plus(b)
print("a = $a \t")

a = 10
a -= b                          等價於  a = a.minus(b)
print("a = $a \t")

a = 10
a *= b                          等價於  a = a.tiems(b)
print("a = $a \t")

a = 10
a /= b                          等價於  a = a.div(b)
print("a = $a \t")

a = 10
a % b                          等價於  a = a.rem(b)
print("a = $a \t")
複製程式碼

輸出結果為:

c = Kotlin10 	a = 12 	a = 8 	a = 20 	a = 5 	a = 0 	
複製程式碼

或許你會說這裡為什麼沒有Kotlin的版本呢?你在看官方文件或者其他人一些部落格文章的時候可能有這樣a += b <=> a.plusAssign()的操作。但是我告訴你a.plusAssign()不是這樣用的,你可以看原始碼知道primitives.kt檔案中肯本就不存在plusAssign()這個方法。因為Koltin賦值不是表示式。即 a += b <=> a = a + bKotlin中是a = a.plus(b)。不過陣列與集合是同時存在plus()plusAssign()這兩個函式的。

還有一點就是:如果我的第一個運算元定義為val(不可變)型別時,a += b這個表示式會編譯出錯。

上面說到了在原始碼primitievs.kt檔案中不存在plusAssign()minusAssign()timesAssign()divAssign()remAssign()這些方法。那為什麼官方文件上會存在呢?這裡這裡不做詳解,但是我會在自定義過載操作符方法的時候給大家說明,請大家詳細的往下看,一些更高階的操作

2.3、位運算操作

位運算操作:即對一個數進行位移運算。關於這個操作符的過載函式,我在前面講解資料型別章節的時候已經講解過,這裡就不多做累述了。沒有看過的朋友請參見Kotlin——初級篇(三):資料型別詳解

2.4、區間操作

區間操作符:即是符號..。值得注意的是這個操作符在Java中是不存在的,且兩個運算元都是整型

操作符 表示 過載
a .. b a 到 b 中間的值 a.rangeTo(b)

這個操作符一般用於for迴圈中,在條件判斷中偶爾也會用到。

例:

val a = 1
val b = 5

// 操作符實現
val s = 3 in a .. b     // true,因為3在區間[1,5]之內
println("s = $s")
for (index in a .. b){
    print("index = $index \t")
}

// 操作符過載方式實現
val t = 3 in a.rangeTo(b)
println("t = $t")
for (index in a.rangeTo(b)){
    print("index = $index \t")
}
複製程式碼

輸出結果為:

s = true
index = 1 	index = 2 	index = 3 	index = 4 	index = 5 	
t = true
index = 1 	index = 2 	index = 3 	index = 4 	index = 5 
複製程式碼

當然了,這些例項都是極其簡單的。我在Kotlin——初級篇(四):控制語句講解這篇文章也是講到過的。

總結

關於操作符過載,這裡由於篇幅過長的原因,後面的比較操作符,以及inis、以及自定義操作符等都會在下一章講解。敬請期待...

這篇文章,主要講解了Kotlin中常用的操作符以及過載方法。其中的第一部分只是介紹了其概念,在第二節在才開始講解了其用法及例項說明。重點在於二元操作中的複合運算一節,千萬不要被別人的部落格和翻譯文件所誤導。上面的例項都是我一個一個實驗過後才寫出來的。實踐出真理,不然我也不知道這個a += b等所 對應的a.plusAssign(b)等會這麼坑。

參考

這裡參考了別人翻譯的官方文件
以及另外一篇很好的博文

原始碼

如果各位大佬看了之後感覺還闊以,就請各位大佬隨便star一下,您的關注是我最大的動力。
我的個人部落格Jetictors
我的githubJetictors

歡迎各位大佬進群共同研究、探索

QQ群號:497071402

Kotlin——初級篇(五):操作符與操作符過載一

相關文章