您的位置:首页 > 其它

Kotlin语法(十)-扩展

2016-09-03 09:57 162 查看
         参考原文:http://kotlinlang.org/docs/reference/extensions.html

         类似于C#和Gosu,Kotlin提供了不用继承父类,或者使用像装饰模式这样的设计模式方式来给某个类进行扩展功能(Extensions)。

扩展类型支持:函数和属性。

     扩展函数

         下面方式进行函数扩展:swap为扩展的函数。

funMutableList<Int>.swap(index1: Int, index2: Int) {

  val tmp = this[index1] // 'this' correspondsto the list

  this[index1] = this[index2]

  this[index2] = tmp

}
         

         添加扩展函数后,就可以对“MutableList<Int>”实例使用扩展的函数:

val tempM = mutableListOf(1, 2, 3) //[1, 2,3]

tempM.swap(0,1) //[2, 1, 3]
 

       扩展是一种静态方式(Extensions are resolved statically)

         扩展实际没有修改扩展类;当定义一个扩展,并没有增加一个成员到扩展类中,仅仅是在扩展类实例可以通过“.”方式使用该扩展功能。

         调用扩展功能,调用的是实例定义类型对应的扩展,而不是实例的实际类型对应的扩展。

open class C

class D: C()

 

fun C.foo() ="c"

fun D.foo() ="d"

 

fun printFoo(c: C){

    println(c.foo())

}

 

printFoo(D()) //result is “c”
         实际传入的参数为D的实例,但最后调用的是C的扩展函数,因为在定义时参数对应的类型为C。

 

         类有一个函数,再给该类定义一个相同名称的扩展函数,则该类的实例调用的为类原有的函数。

class C {

    fun foo() { println("member") }

}

 

fun C.foo() {println("extension") }

 

val c = C()

c.foo() //result is “member”
         若是重载(函数名称相同,参数不同)方式扩展一个函数,则根据参数调用到不同的函数:

class C {

    fun foo() { println("member") }

}

 

fun C.foo(i: Int) {println("extension") }

val c = C()

c.foo(1) //result is “extension”
 

       可空接收器(Nullable Receiver)

         扩展可以定义一个可空的接收类型;该种扩展可以使用一个null对象调用,可以在扩展函数中使用“
this == null
 ”来检测为空状态。

         下面的实例,可以不用判定实例是否为空,就直接调用“toString()”函数,在该扩展函数内部进行为空判定。

fun Any?.toString(): String {

    if (this == null) return "null"

    // after the null check, 'this' is autocastto a non-null type, so the toString() below

    // resolves to the member function of theAny class

    return toString()

}
 

     扩展属性(Extension Properties)

         Kotlin支持扩展属性,跟扩展函数语法类型,直接在类名后通过“.”方式添加扩展:

val <T>List<T>.lastIndex: Int

    get() =size - 1
         扩展的属性不是在原类中增加相关属性:

         Ø  扩展属性没有“backing field

         Ø  扩展属性不支持默认初始化;需要明确定义“ getters/setters”

valFoo.bar = 1 // error: initializers are not allowed for extension properties
 

     友元(伴侣)对象扩展(Companion Object Extensions)

         静态属性(Kotlin中去掉了static,用companion object{ … }方式定义静态函数及属性)的扩展:若一个类中已经有定义“companion object”,则可以对该类“companion object”进行扩展:

class MyClass {

  companion object { }  // will be called "Companion"

}

funMyClass.Companion.foo() {

  // ...

}

 

//直接使用类名调用扩展

MyClass.foo()
 

     扩展范围(Scope of Extensions)

         一般都是在顶层(top level)定义扩展,如:

package foo.bar

 

fun Baz.goo() { ... }
         那么在该包的外面使用该扩展,需要在使用时导入该扩展:

packagecom.example.usage

 

import foo.bar.goo// importing all extensions by name "goo"

                // or

import foo.bar.*   // importing everything from"foo.bar"

 

fun usage(baz: Baz){

  baz.goo()

}
 

     作为成员扩展(Declaring Extensions as Members)

         在一个类中,可以为另外一个类添加扩展。在这样的一个扩展中,可以直接调用外部类的成员。

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@ClassName”方式:

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 virtually

C().caller(D1())  // prints "D.foo in C" - extension receiver is resolved statically

C1().caller(D1())  // prints "D.foo in C1"
 

     设计扩展的目的(Motivation)

         比如在Java中,集合操作的swap 方法的API设计:

// Java

Collections.swap(list, i, j)
         这种方式在使用的时候,就感觉不是很流畅,本来需要交换list中的i j两个位置的值,而使用方式确是将[list, i, j]三个参数传入到一个方法中。

         比较流畅的方式应该是list. swap(i, j),本身该操作对应list;但是很多时候API已经设计好或者不能实现所有的可能的方法;这时候可以通过扩展方式来灵活实现需要的功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: