Kotlin中的扩展函数

前言

Kotlin是一种在Java虚拟机上运行的静态类型编程语言,被称之为Android世界的Swift,在GoogleI/O2017中,Google宣布Kotlin成为Android官方开发语言

什么是扩展函数

扩展函数就是可以在类的外部声明额外的类的函数,并且可以扩展系统函数,让使用更方便,代码更简洁

举个例子,TextView是我们常用的组件,通常情况下我们会在布局或者代码中调用setText函数,对其进行内容设置,当我们需要当设置内容为空的时候我们显示NaN,通常我们可以这样做

fun setTextOptional(textView: TextView, text: String?) {
    textView.text = if (text.isNullOrEmpty()) {
        "NaN"
    } else {
        text
    }
}
setTextOptional(textView, "complete")
setTextOptional(textView, null)
setTextOptional(textView, "inprogress")

上述的处理方式可以达到我们的需求,我们之所以这么做是因为TextView本身并不支持"NaN"的处理,如果我们可以扩展TextView给它添加一个setTextOptional函数那就更好了,扩展函数就可以做到

扩展函数的定义

fun receiverType.functionName(params){
    body
}

扩展函数一般定义在顶层位置,一般用于功能的扩展,不会影响原来类的结构,不用继承或者装饰就直接可以扩展类的内容

receiverType表示要扩展的目标类
functionName表示扩展函数名称
params扩展函数的参数

基于上述的案例,我们需要扩展TextView的功能,那么就可以这样定义,函数内部可以使用this拿到当前的调用对象,当然this也可以省略

fun TextView.setTextOptional(text: String?) {
    this.text = if (text.isNullOrEmpty()) {
        "NaN"
    } else {
        text
    }
}

然后就可以直接这样,更加直观的使用,也更加简单

textView.setTextOptional("complete")
textView.setTextOptional(null)
textView.setTextOptional("inprogress")

上述代码其实会编译成这样的java代码

public static final void setTextOptional(@NotNull TextView $this$setTextOptional, @Nullable String text) {
    $this$setTextOptional.setText((CharSequence)(var6 ? "NaN" : text));
}

扩展函数的静态解析

使用官方的例子,子类与父类扩展了相同的函数,调用时不会根据运行时具体类型去判断,而是由函数调用位置的表达式类型所确定的

open class Shape

class Rectangle: Shape()

fun Shape.getName() = "Shape"

fun Rectangle.getName() = "Rectangle"

fun printClassName(s: Shape) { //此处定义s的类型为Shape
    println(s.getName())
}    

printClassName(Rectangle()) //Shape

扩展函数与成员函数的冲突

如果扩展函数与成员函数拥有相同的函数签名,则总是取成员函数,应该使用重载或者不同的命名方式去避免这种问题的出现

class Example {
    fun printFunctionType() { println("Class method") }
}

fun Example.printFunctionType() { println("Extension function") }

Example().printFunctionType()

可空的接受者

前面我们使用到了isNullOrEmpty函数,它可以使用空对象去调用,因为在这里它声明了CharSequence调用对象可以为空

public inline fun CharSequence?.isNullOrEmpty(): Boolean {
    contract {
        returns(false) implies (this@isNullOrEmpty != null)
    }

    return this == null || this.length == 0
}

可空的接受者,可以减少外部调用的额外判断

fun TextView?.setTextOptional(text: String?) {
    this?.text = if (text.isNullOrEmpty()) {
        "NaN"
    } else {
        text
    }
}

使用BindingAdapter在布局中扩展函数

上述我们扩展了TextView的函数,让其在代码中可以直接调用扩展函数进行额外的功能,那么很多时候我们需要在布局中进行内容的绑定,就像android:text="Login"一样,我们需要使用到DataBinding提供的BindingAdapter对扩展函数进行注解即可在布局中使用扩展函数

@BindingAdapter("textOptional")
fun TextView?.setTextOptional(text: String?) {
    this?.text = if (text.isNullOrEmpty()) {
        "NaN"
    } else {
        text
    }
}

在布局中使用




    

        
    

    

        

    

class LoginActivity : DaggerAppCompatActivity() {

    val binding: AtctivityLoginBinding by ViewDelegate(R.layout.atctivity_login)
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.setStatus(Response("1", ""))
}

欢迎关注Mike的

Android知识整理

你可能感兴趣的:(Kotlin中的扩展函数)