Kotlin語法(其他)


三、其他

1. 多重聲明

有時候可以通過給對象插入多個成員函數做區別是很方便的:

val (name, age) = person

多重聲明一次創建了多個變量。我們聲明了倆個新變量:name age 並且可以獨立使用:

println(name)
println(age)

也可以在 for 循環中用:

for ((a, b) in collection) { ... }

map:

for ((key, value) in map) { ... }

2. Ranges

函數操作符是:

if (i in 1..10){ ... }
if (x !in 1.0..3.0) println(x)
if (str in "island".."isle") println(str)
for (i in 4 downTo 1) print(i) // prints '4321'
for (i in 1..4 step 2) print(i) // prints "13"
for (i in 4 downTo 1 step 2) print(i) // prints "42"
for (i in 1.0..2.0 step 0.3) print("$i ") // prints "1.0 1.3 1.6 1.9 "
for (i in (1..4).reversed()) print(i) // prints "4321"
for (i in (1..4).reversed() step 2) print(i) // prints "42"

3. 類型檢查和轉換

is !is 表達式: 類似Java的instanceof

“不安全”的轉換符,如下的x不能為空,否則拋異常:

val x: String = y as String

"安全"轉換符,如下不管 as? 右邊的是不是一個非空 String 結果都會轉換為可空的:

val x: String ?= y as? String

4. This 表達式

如果 this 沒有應用者,則指向的是最內層的閉合范圍。為了在其它范圍中返回 this ,需要使用標簽:this@lable

5. 等式

在 kotlin 中有兩種相等:

  • 參照相等: ===,參照相等是通過 === 操作符判斷的(不等是!== ) a===b 只有 a b 指向同一個對象是判別才成立。另外,你可以使用內聯函數identityEquals() 判斷參照相等。

  • 結構相等: ==,結構相等是通過 == 判斷的。像a == b將會翻譯成:a?.equals(b) ?: b === null,如果 a 不是 null 則調用 equals(Any?) 函數,否則檢查 b 是否參照等於 null。

6. 運算符重載

http://kotlinlang.org/docs/reference/operator-overloading.html

7. 空安全

var a: String ="abc"
a = null // 編譯錯誤
val l = a.length() // 因為a不能為null,所以不會報錯
var b: String? = "abc"
b = null
val l = b.length() // 錯誤:b為空
val l = if (b != null) b.length() else -1 // 不會報錯
b?.length() // 安全調用不會報錯

安全調用在鏈式調用是是很有用的。比如,如果 Bob 是一個雇員可能分配部門(也可能不分配),如果我們想獲取 Bob 的部門名作為名字的前綴,就可以這樣做:

bob?.department?.head?.name // 

Elvis 操作符:

val l: Int = if (b != null) b.length() else -1

也可以使用 Elvis 操作符?::

val l = b.length()?: -1

如果 ?: 左邊表達式不為空則返回,否則返回右邊的表達式。注意右邊的表帶式只有在左邊表達式為空是才會執行。

!!操作符:
第三個選擇是 NPE-lovers。我們可以用 b!! ,這會返回一個非空的 b 或者拋出一個 b 為空的 NPE:

val l = b !!.length()

安全轉換:
普通的轉換可能產生 ClassCastException 異常。另一個選擇就是使用安全轉換,如果不成功就返回空:

val aInt: Int? = a as? Int

8.異常

所有的異常類都是 Exception 的子類。使用方式與Java類似。

try {
  // some code
}
catch (e: SomeException) {
  // handler
}
finally {
  // optional finally block
}

9.注解

注解是一種將元數據附加到代碼中的方法。聲明注解需要在類前面使用 annotation 關鍵字:

annotation class fancy

用法:在多數情形中 @ 標識是可選的。只有在注解表達式或本地聲明中才必須

@fancy class Foo {
    @fancy fun baz(@fancy foo: Int): Int {
        return (@fancy 1)
    }
}
// 可省略@
fancy class Foo {
    fancy fun baz(fancy foo: Int): Int {
        @fancy fun bar() { ... }
        return (@fancy 1)
    }
}

如果要給構造函數注解,就需要在構造函數聲明時添加 constructor 關鍵字,並且需要在前面添加注解:

class Foo @inject constructor (dependency: MyDependency)

注解可以有帶參數的構造函數:

annotation class special(val why: String)
special("example") class Foo {}

注解也可以用在 Lambda 中。這將會應用到 lambda 生成的 invoke() 方法:

annotation class Suspendable
val f = @Suspendable { Fiber.sleep(10) }

java 注解在 kotlin 中是完全兼容的。
如果java 中的 value 參數有數組類型,則在 kotlin 中變成 vararg 參數:

// Java
public @interface AnnWithArrayValue {
    String[] value();
}
// Kotlin
AnnWithArrayValue("abc", "foo", "bar") class C

注解實例的值在 kotlin 代碼中是暴露屬性。

10.反射

得到運行時的類引用:

val c = MyClass::class

引用是一種 KClass類型的值。你可以使用KClass.propertiesKClass.extensionProperties獲取類和父類的所有屬性引用的列表。

函數引用
使用::操作符:

fun isOdd(x: Int) =x % 2 !=0
val numbers = listOf(1, 2, 3)
println(numbers.filter( ::isOdd) ) //prints [1, 3]

這里::isOdd是是一個函數類型的值(Int) -> Boolean

下面是返回一個由兩個傳遞進去的函數的組合。現在你可以把它用在可調用的引用上了:

fun compose<A, B, C>(f: (B) -> C, g: (A) -> B): (A) -> C {
    return {x -> f(g(x))}
}

fun length(s: String) = s.size
val oddLength = compose(::isOdd, ::length)
val strings = listOf("a", "ab", "abc")
println(strings.filter(oddLength)) // Prints "[a, abc]"

屬性引用
訪問頂級類的屬性,我們也可以使用::操作符:

var x = 1
fun main(args: Array<String>) {
    println(::x.get())
    ::x.set(2)
    println(x)
}

::x表達式評估為KProperty<Int>類型的屬性,它允許我們使用get()讀它的值或者使用名字取回它的屬性。

class A(val p: Int)

fun main(args: Array<String>) {
    val prop = A::p
    println(prop.get(A(1))) // prints "1"
}

對於擴展屬性:

val String.lastChar: Char
  get() = this[size - 1]

fun main(args: Array<String>) {
  println(String::lastChar.get("abc")) // prints "c"
}

與 java 反射調用
想找到一個備用字段或者 java getter 方法:

import kotlin.reflect.jvm.*

class A(val p: Int)

fun main(args: Array<String>) {
    println(A::p.javaGetter) // prints "public final int A.getP()"
    println(A::p.javaField)  // prints "private final int A.p"
}

構造函數引用
只需要使用::操作符並加上類名。下面的函數是一個沒有參數並且返回類型是Foo:

calss Foo
fun function(factory : () -> Foo) {
    val x: Foo = factory()
}
function(:: Foo)

11. 動態類型

為了方便使用,dynamic應而生:

val dyn: dynamic = ...

dynamic類型關閉了 kotlin 的類型檢查:

這樣的類型可以分配任意變量或者在任意的地方作為參數傳遞 任何值都可以分配為dynamic 類型,或者作為參數傳遞給任何接受 dynamic 類型參數的函數 這樣的類型不做 null 檢查

dynamic最奇特的特性就是可以在dynamic變量上調用任何屬性或任何方法。

dyn.whatever(1, "foo", dyn) // 'whatever' is not defined anywhere
dyn.whatever(*array(1, 2, 3))

動態調用可以返回dynamic作為結果,因此我們可以輕松實現鏈式調用:

dyn.foo().bar.bat()

當給動態調用傳遞一個 lambda 表達式時,所有的參數默認都是dynamic

dyn.foo {
  x -> x.bar() // x is dynamic
}

參考:

  1. http://kotlinlang.org/docs/reference/basic-syntax.html
  2. http://huanglizhuo.gitbooks.io/kotlin-in-chinese


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM