常量和變量
fun main() {
//變量
var a: Int = 2
a = 3
//只讀變量,在局部中,和 final 相同
val b = 2
//如果是全局
val x = X()
println(x.b) //每次的值都不一樣
/**
* 長量引用
* 創建的對象在 堆 上
* 對象內部內容可以改變,但是對象不能改變
*/
val x1 = X()
}
/**
* 常量
* 只能定義在全局範圍
* 只能修飾基本類型
* 必須立即用字變量初始化
* 和 java 中的 static final 基本相同
*/
const val b = 2 // 編譯時即可確定常量的值,並用值替換調用處
val c: Int //運行時才能確定值
get() {
TODO()
}
class X {
//屬性
val b: Int
get() {
return (Math.random() * 100).toInt()
}
}
分支表達式
fun main() {
var c = 4
// if else 表達式
c = if (c == 4) 3 else 9
println(c)
//分支,類似於 switch,但是不用寫 break
when (c) {
0 -> c = 2
1 -> c = 3
else -> c = 20
}
//簡化
c = when (c) {
0 -> 2
1 -> 3
else -> 20
}
//條件轉移到分支
var x: Any = ""
when {
x is String -> x = "哈哈哈"
x is Int -> x = 10
else -> x = 90
}
//簡化
x = when (x) {
is String -> "哈哈哈"
is Int -> 10
else -> 90
}
//when...
x = when (val input = readLine()) {
null -> ""
else -> input.length
}
//try ... catch 表達式
x = try {
3 / 0
} catch (e: Exception) {
e.printStackTrace()
0
}
}
運算符
-
Kt 中支持運算符重載
-
運算符的範圍僅限官方指定的符號
Kt 允許我們爲自己的類型提供預定義的一組操作符的實現,這些操作符舉要固定的符號表示,如 + * 等。爲實現這樣的操作符,Kt 爲相應的類型提供了一個固定名字的成員函數或者擴展函數。重載操作符需要使用 operator 修飾符標記。
如下:
fun main() {
val point = Point(10, 20)
println(point - 10) //0
}
class Point(val x: Int, val y: Int) {
//重載 - 號
operator fun minus(num: Int): Int {
return x - num
}
}
fun main() {
val point = Point(10, 20)
println(point[0]) //10
println(point[1]) //20
println(point[2]) //java.lang.IndexOutOfBoundsException
}
class Point(val x: Int, val y: Int) {
//重載 get
operator fun get(index: Int): Int {
return when (index) {
0 -> x
1 -> y
else -> throw IndexOutOfBoundsException()
}
}
}
官方中文文檔
中綴表達式
fun main() {
println("Hello" to "Word")
}
/**
* 中綴表達式
* 必須加 infix 標識
* 只有一個參數,並且是擴展方法
*/
infix fun String.rotate(str: String): String {
return this + str
}
函數的表達式形式
fun main() {
println(add(1, 2))
println(add2(2, 3))
}
fun add(x: Int, y: Int): Int {
return x + y
}
//如果函數中只有一句或者爲一個表達式,可以這樣寫
fun add2(x: Int, y: Int): Int = x + y
Lambad 表達式
fun main() {
/**
* 將匿名函數賦值給一個變量
* fun1 是變量名
* 調用 fun1()
*/
val fun1 = fun() {
println("匿名函數")
}
//Lambad 其實就是匿名函數
val l1 = {
println("lambad")
}
//帶參數的 Lambad
val l2 = { p: Int ->
println("帶參數的 Lambad")
}
// 表達式中最後一行爲返回值,可不加 return
val l3 = { p: Int ->
println(p)
"Hello Word"
}
//表達式中如果只有一個參數,可以用 it 代替
val l4: Function1<Int, Unit> = {
println(it)
}
l4(123)
//第二個參數接收一個Lambad 表達式,接收一個 Int 參數,並返回一個 Int 參數
IntArray(2) { i ->
0
}
fun3() { x: Int, y: Int ->
println("${x + y}")
"$x + $y"
}
}
//接收兩個 int 類型,返回一個 String 類型的函數
fun fun3(sum: (Int, Int) -> String) {
println(sum(2, 3))
}
fun fun0() {
println("普通函數")
}
案例1
實現 equals 和 hashCode
fun main() {
val hashSet = hashSetOf<Person>()
(0..5).forEach { _ ->
hashSet += Person(30, "張三")
}
println(hashSet.size)
//注意:將對象添加到集合後就不要改變對象的數據,否則會造成無法刪除,從而引發內存泄露
}
class Person(private val age: Int, private val name: String) {
override fun equals(other: Any?): Boolean {
val o = (other as? Person) ?: return false
return age == o.age && name == o.name
}
override fun hashCode(): Int {
return 31 + age * 7 + name.hashCode()
}
}
案例2
實現 String 的四則運算
fun main() {
val value = "HelloWorld"
println(value - "World")
println(value * 3)
println(value / "l")
}
// - 替換第一個出現的字符串
operator fun String.minus(right: Any?): String =
this.replaceFirst(right.toString(), "")
// * 鏈接一個字符串
operator fun String.times(count: Int): String {
return (1..count).joinToString(" ") { this }
}
// / 找出出現多少次
operator fun String.div(right: Any?): Int {
val r = right.toString()
//根據傳入的字符串,從 this 中挨個進行查找
//如 length = 2,那就是 " he , el ,ll ,lo , ow ... "
//最後一個參數是表達式,所以可以移到外面
return this.windowed(r.length, 1) {
//判斷是否相等
it == r
}.count {
//計數,
it
}
}
總結
- 常量和變量
- 定義方式:var / val /const val
- 常量按類型分類
- 常量值
- 常量引用
- 常量按時期分類
- 編譯器常量
- 運行時常量
- 分支表達式
- if else
- when …
- try … catch
- 運算符
- 常見的運算符
- “+ - * /”
- “. < ==”
- “ in ”
- " get "
- " invoke "
- 運算符的重載
- 中綴表達式:必須有 infix 標識,是擴展方法,並且只有一個參數
- 函數的表達式形式:如果函數中只有一句話或者一個表達式,可直接賦值給 函數
- 常見的運算符
- Lambad
- 匿名函數 :本質是匿名函數,匿名函數不能直接使用,需要一個變量來接收,然後調用這個變量就能間接的調用這個匿名函數
- 寫法
- 類型
- 類型推斷:如果左邊定義中已經寫了具體的類型聲明,後面的實現就可以不用寫。反之,後面則需要具體的聲明
參考自慕課網 Kotlin 從入門到精通