Better

业精于勤荒于嬉

Idiomatic Kotlin:extension function and Variable

Better's Avatar 2019-05-26 Kotlin

  1. 1. define and use
  2. 2. bummock
  3. 3. private
  4. 4. Inheritance
  5. 5. as member
  6. 6. name conflict
  7. 7. 参考

extension 既扩展。在 kotlin 中可以不使用继承的方式,向类型中添加方法和变量。

比如在使用一些第三方的代码时,可以通过扩展直接向这些类中添加一些方法、变量,而不需要集成这些类来添加方法、变量。减少了一些不别要的派生类。(motivation)

这样的好处是,可以跟老的代码无缝的集成。

define and use

定义函数Type.xxx(),定义变量Type.xxx
define:

1
2
3
4
5
6
fun String.hello(){
Log.e("Hello","hello world")
}

val String.hello: String
get() = "hello world"

use:

1
2
"world".hello()
val world = "world".hello

bummock

Tools -> Kotlin -> Show Kotlin ByteCode点击Decompile 按钮查看生成的代码

1
2
3
4
5
6
7
8
9
10
11
12
public final class AKt {
public static final void hello(@NotNull String $this$hello) {
Intrinsics.checkParameterIsNotNull($this$hello, "$this$hello");
Log.e("Hello", "hello world");
}

@NotNull
public static final String getHello(@NotNull String $this$hello) {
Intrinsics.checkParameterIsNotNull($this$hello, "$this$hello");
return "hello world";
}
}

扩展函数 ,其实并没有真正的向类型中添加新的函数,而是通过静态方法来实现的
扩展变量,也只是通过静态方法来实现的,所有在定义的时候,必需写getter()

private

由于扩展函数并不是真正的向类型中增加函数。所以不能访问类型中的私有属性以及方法。

Inheritance

没有继承多态的效果。子类和父类申明扩展方法的时候,调用时,不管子类还是父类调用,始终至于父类的有效

1
2
3
4
5
6
7
open class Feline
fun Feline.speak() = "<generic feline noise>"
class Cat : Feline()
fun Cat.speak() = "meow!!"
fun printSpeak(feline: Feline) {
println(feline.speak())
}
1
2
printSpeak(Feline())
printSpeak(Cat()

result:

1
2
<generic feline noise>
<generic feline noise>

as member

扩展函数可以定义在类中作为一个普通的函数,这样就具有多态。这种情况需要区分this,this@Class

1
2
3
4
5
6
7
8
9
10
open class Caregiver(val name: String) {
open fun Feline.react() = "PURRR!!!"
fun Primate.react() = "*$name plays with ${this@Caregiver.name}*"
fun takeCare(feline: Feline) {
println("Feline reacts: ${feline.react()}")
}
fun takeCare(primate: Primate){
println("Primate reacts: ${primate.react()}")
}
}
1
2
3
4
5
val adam = Caregiver("Adam")
val fulgencio = Cat()
val koko = Primate("Koko")
adam.takeCare(fulgencio)
adam.takeCare(koko)

result:

1
2
PURRR!!!
*Koko plays with Adam*

name conflict

扩展函数和成员函数同名是支持的。

  • 默认执行的是成员函数,扩展函数是不会调用的。
  • 但是当成员函数是私有的时,是调用的扩展函数(因为无法访问私有的成员函数)
1
2
3
4
5
6
7
class Worker {
fun work() = "*working hard*"
private fun rest() = "*resting*"
}
fun Worker.work() = "*not working so hard*"
fun <T> Worker.work(t:T) = "*working on $t*"
fun Worker.rest() = "*playing video games*"
1
2
3
4
val worker = Worker()
println(worker.work())
println(worker.work("refactoring"))
println(worker.rest())

result:

1
2
3
*working hard*
*working on refactoring*
*playing video games*

参考

Idiomatic Kotlin: Extension functions
functional_kotlin

This article was last updated on days ago, and the information described in the article may have changed.