目录
这一节主要介绍顶层函数和属性,扩展函数和属性的原理,理解它们与Java的区别,并提出局部函数的概念
1. 顶层函数和属性
顶层函数不属于任何类,可以理解成Java的静态函数
//在Join.kt文件中
package strings
fun joinToString(...): String { ... }
const val UNIX_LINE_SEPARATOR = "\n"
相当于Java代码中的
package strings;
public class JoinKt {
public static String joinToString(...) { ... }
public static final String UNIX_LINE_SEPARATOR = "\n";
}
2. 扩展函数
//ExtendsionTextView.kt文件中
//扩展函数定义
fun TextView.isBold() = this.apply {
paint.isFakeBoldText = true
}
//扩展函数调用
activity.find<TextView>(R.id.course_comment_tv_score).isBold()
等同于下面的 Java 代码:
public final class ExtendsionTextViewKt {//这个类名就是顶层文件名+“Kt”后缀,这个知识上篇博客有详细介绍
public static final TextView isBold(@NotNull TextView $receiver) {//扩展函数isBold对应实际上是Java中的静态函数,并且传入一个接收者类型对象作为参数
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
$receiver.getPaint().setFakeBoldText(true);//设置加粗
return $receiver;//最后返回这个接收者对象自身,以致于我们在Kotlin中完全可以使用this替代接收者对象或者直接不写。
}
}
实际上就是一个静态函数,静态函数参数是接受者类型的对象,利用这个对象就可以访问这个对象里面的所有东西,所以相当于扩展了,扩展属性是怎么实现的呢?各位可以先思考一下,再看下面。
3. 扩展属性
//ExtendsionTextView.kt文件中
//扩展属性定义
var TextView.isBolder: Boolean
get() {//必须定义get()方法,因为不能在现有对象添加字段,也自然就没有了默认的get()实现
return this.paint.isFakeBoldText
}
set(value) {
this.paint.isFakeBoldText = true
}
//扩展属性调用
activity.find<TextView>(R.id.course_comment_tv_score).isBolder = true
等同于下面的 Java 代码:
public final class ExtendsionTextViewKt {
//get()方法所对应生成静态函数,并且传入一个接收者类型对象作为参数
public static final boolean isBolder(@NotNull TextView $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return $receiver.getPaint().isFakeBoldText();
}
//set()方法所对应生成静态函数,并且传入一个接收者类型对象作为参数和一个需要set的参数
public static final void setBolder(@NotNull TextView $receiver, boolean value) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
$receiver.getPaint().setFakeBoldText(true);
}
}
其实就是在get和set方法中加入了接受者类型的对象,利用这个对象就可以访问这个对象里面的所有东西
但是以为扩展函数和属性是静态的,所以是不能够重写的
4. 局部函数
class User(val id: Int, val name: String, val address: String)
fun saveUser(user: User) {
if (user.name.isEmpty()) {
throw IllegalArgumentException("用户名为空不能保存")
}
if (user.address.isEmpty()) {
throw IllegalArgumentException("用户地址为空不能保存")
}
//保存user
}
把其中检验字段的代码整个成一个验证的局部函数
fun saveUser(user: User) {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("用户${user.fieldName} 为空不能保存") //局部函数能访问外部函数的user对象
}
}
validate(user.name, "名")
validate( user.address, "地址")
//保存user
}
当然,你也可以用将这段局部函数直接放进扩展函数中
fun User.validateBeforeSave() {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("用户$fieldName 为空不能保存")
}
}
validate(name, "名")
validate(address, "地址")
}
fun saveUser(user: User) {
user.validateBeforeSave()
//保存user
}