Kotlin Reference (十二) Extensions
来源:互联网 发布:淘宝头条怎么申请 编辑:程序博客网 时间:2024/06/06 12:54
most from reference
Kotlin与C#和Gosu类似,提供了扩展一个新功能的类,而不必继承类或使用任何类型的设计模式,如Decorator(装饰者模式)。这是通过称为扩展的特殊声明完成的。Kotlin支持扩展功能和扩展属性。
扩展功能
要声明一个扩展函数,我们需要一个接收器类型(即被扩展的类型)作为其名称的前缀。以下是为MutableList扩展的swap功能:
fun MutableList<Int>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp}
扩展功能中的this关键字对应于接收器对象(在.之前传递的对象)。现在我们可以在任何时候调用MutableList的这个函数:
val l = mutableListOf(1, 2, 3)l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'
当然,这个功能对任何MutableList都是有用的,我们可以 让其更加通用:
fun <T> MutableList<T>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp}
我们在函数名称之前声明通用类型参数,使其在接收器类型表达式中可用。请参考通用功能
扩展函数静态解析
扩展实际上不会修改他们扩展的类。通过定义扩展名,不会将新成员插入到类型,而只是使用这种类型的变量上点符号来调用新的函数。
需要强调的是,扩展功能是静态调用的,它们不是虚拟的接收器类型。这意味着被调用的扩展函数由调用该函数的表达式的类型决定,而不是在运行时评估该表达式的结果的类型。例如:
open class Cclass D: C()fun C.foo() = "c"fun D.foo() = "d"fun printFoo(c: C) { println(c.foo())}printFoo(D())
此例将先打印”c”,因为被调用的扩展函数仅取决于声明的参数类型c,即C类。
如果一个类有一个成员函数,并且定义了一扩展函数,它具有相同的接收器类型,相同的名称,并且适用于给定的参数,则成员函数的优先级更高。例如:
class C { fun foo() { println("member") }}fun C.foo() { println("extension") }
如果我们调用c.foo(),它将打印”member”而不是”extension”。
但是,扩展函数可以重载具有相同名称不同参数的成员函数,这是完全可行的:
class C { fun foo() { println("member") }}fun C.foo(i: Int) { println("extension") }
调用C().foo(1)将打印”extension”。
空接收器
我们可以使用空接收器类型定义扩展。这样的扩展可以在对象变量上调用,即使他的值为null,并且可以在方法体内检查this==null。这样就可以在Kotlin中调用toString()而无需检查null:检查发生在扩展函数内。
fun Any?.toString(): String { if (this == null) return "null" // after the null check, 'this' is autocast to a non-null type, so the toString() below // resolves to the member function of the Any class return toString()}
扩展属性
与扩展函数类似,Kotlin支持扩展属性:
val <T> List<T>.lastIndex: Int get() = size - 1
请注意,由于扩展名实际上并没有将成员插入到类中,因此扩展属性没有有效的备份字段。这就是为什么不允许扩展属性的初始化。它们的行为只能通过提供明确getter/setter来定义。
val Foo.bar = 1 // error: initializers are not allowed for extension properties
伴生对象扩展
如果一个类定义了一个伴生对象,那么还可以定义该对象的扩展函数和属性:
class MyClass { companion object { } // will be called "Companion"}fun MyClass.Companion.foo() { // ...}
就像伴生对象的常规成员一样,只能使用该类名作为限定词:
MyClass.foo()
扩展范围
大多数时候我们在顶层定义扩展,即直接在包下:
package foo.barfun Baz.goo() { ... }
要在其声明包之外使用这样的扩展,我们需要在调用的地方导入它:
package com.example.usageimport foo.bar.goo // importing all extensions by name "goo" // orimport foo.bar.* // importing everything from "foo.bar"fun usage(baz: Baz) { baz.goo()}
有关详细信息,请参考导入。
作为成员函数定义扩展函数
在类中,您可以为另一个类声明扩展名。在这样的扩展中,有多个隐式接收器,可以在没有限定符的情况下访问对象成员。声明扩展名的类的实例为调用接收方,扩展方法的接收方类型称为扩展接收方。
class D { fun bar() { ... }}class C { fun baz() { ... } fun D.foo() { bar() // calls D.bar baz() // calls C.baz } fun caller(d: D) { d.foo() // call the extension function }}
在发送接收机的成员分机接受者之间发生姓名冲突的情况下,分机接受者优先。要引用法发送接收器的成员,您可以使用this语法。
class C { fun D.foo() { toString() // calls D.toString() this@C.toString() // calls C.toString() }
作为成员的扩展可以用open声明在类中覆盖。这意味着这种功能的调用对于调用接收器类型是虚拟的,但是关于扩展接收器类型时静态的。
open class D {}class D1 : D() {}open class C { open fun D.foo() { println("D.foo in C") } open fun D1.foo() { println("D1.foo in C") } fun caller(d: D) { d.foo() // call the extension function }}class C1 : C() { override fun D.foo() { println("D.foo in C1") } override fun D1.foo() { println("D1.foo in C1") }}C().caller(D()) // prints "D.foo in C"C1().caller(D()) // prints "D.foo in C1" - dispatch receiver is resolved virtuallyC().caller(D1()) // prints "D.foo in C" - extension receiver is resolved statically
目的
在Java中,我们习惯命名*.utils的类:FileUtils,StringUtils等等。跟ava.util.Collections属于统一类型。
关于这些Utils类令人不快的是使用它们如下例所示:
// JavaCollections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list))
这些类型总是阻碍了我们理解。我们可以使用静态导入:
// Javaswap(list, binarySearch(list, max(otherList)), max(list))
这样使用稍微好点,从强大的代码补全IDE,我们不需要或需要很少的帮助。如果我们这样写,会不会好点:
// Javalist.swap(list.binarySearch(otherList.max()), list.max())
但是我们不想在类中实现所有可能的方法List,对吧?这是扩展帮助我们的地方。
- Kotlin Reference (十二) Extensions
- Kotlin Reference (十二) 内部类、枚举
- Kotlin Reference (十) 类的扩展:class extensions
- < Kotlin > Kotlin Android Extensions (译文)
- Use Kotlin Android Extensions
- kotlin初窥之Kotlin Android Extensions
- Kotlin学习之kotlin-android-extensions
- Kotlin Android Extensions工具使用
- Kotlin Reference (六) 接口
- kotlin Unresolved reference: kotlinx
- Kotlin Reference (二) Idioms
- Kotlin Reference (五) Packages
- Kotlin Reference (十) Interfaces
- Kotlin Reference (十四) Generics
- Kotlin开发Android笔记10:Kotlin中Kotlin Android Extensions
- Android Studio 添加Kotlin extensions支持
- Kotlin-12.扩展函数和属性(extensions)
- Kotlin-Android-Extensions:不仅仅是替代findViewById
- CodeForces 385 E.Bear in the Field(dp+矩阵快速幂)
- 2017第四次多校联合hdu6078
- Postgres-XL9.5集群安装与配置
- 已有文件夹添加到ASP.NET解决方案资源管理器中
- 剑指offer-丑数
- Kotlin Reference (十二) Extensions
- Longest Ordered Subsequence --DP
- 【剑指offer】把数组排成最小的数
- 松果
- 软件安全测试需要更加灵活
- 万能的退出函数exit VS ExitProcess
- Java多态性理解
- 求助求助,更改IP以后,hive启动出问题了。只能找到以前的IP,找不到新的IP
- B