扩展函数

扩展函数表示即使在不修改某个类的源码的情况下,仍然可以打开这个类,向该类添加新的函数

如果想统计字符串中字母的数量,你可能会写出如下函数:

object StringUtil {
    fun letterCount(string: String):Int{
        var count = 0
        for(str in string){
            if(str.isLetter()){
                count++
            }
        }
        return count
    }
}

调用时

StringUtil.letterCount("123abc456def")

有了扩展函数,我们可以使用一种更加面向对象的思维来实现这个功能,比如说将 letterCount() 方法添加到 String 类中

先来学习扩展函数语法结构

fun ClassName.methodName(param1: Int, param2: Int): Int{
	return 0
}

相对于定义一个普通的函数,定义扩展函数只需要在函数名前加上一个 ClassName. 的语法结构,就表示将该函数添加到指定类当中了

由于我们希望向 String 类中添加一个扩展函数,因此需要先创建一个 String.kt 文件。文件名虽无固定要求,但建议向哪个类添加扩展函数,就定义一个同名 Kotlin 文件。当然扩展函数也是可以定义在任何一个现有类当中,不一定非要创建新文件。通常来说,最好将它定义成顶层方法,这样可以让扩展函数拥有全局的访问域

String.kt 中编写如下代码:

fun String.letterCount():Int{
    var count = 0
    for(str in this){
        if(str.isLetter()){
            count++
        }
    }
    return count
}

现在我们将 letterCount() 方法定义成了 String 类的扩展函数,那么函数就拥有了 String 实例的上下文,因此不需要再接收一个字符串参数了,直接遍历 this 即可,因为 this 就代表字符串本身

使用时

"123abc456def".letterCount()

运算符重载

+ - * /等运算符大家都用过,Kotlin 的运算符重载允许我们让任意两个对象进行相加,或者是进行更多其他的运算操作

运算符重载使用的是 operator 关键字,只要在指定函数前面加上 operator 关键字就可以实现运算符重载功能了。我们以加号运算符为例,来实现两个对象相加的功能

class Obj {
    operator fun plus(obj: Obj): Obj {
        //处理相加逻辑
    }
}

上述语法结构中关键字 operater 和函数名 plus 都是固定不变的,接收参数和返回值根据你自己的逻辑设定。那么上述代码就表示一个 Obj 对象可以与另一个 Obj 对象相加,最终返回新的 Obj 对象。对应调用方式如下:

val obj1 = Obj()
val obj2 = Obj()
val obj3 = obj1 + obj2

最后两个对象相加看起来很神奇,它会在编译的时候被转换成 obj1.plus(obj2) 的调用方式

下面实现一个功能:让两个 Money 对象相加

首先定义好 Money 类的结构,让 Money 主构造函数接收一个 value 参数,用于表示钱的金额,然后使用运算符重载实现两个 Money 相加,创建 Money.kt 文件:

class Money(val value:Int){
    operator fun plus(money: Money):Money{
        val sum = value + money.value
        return Money(sum)
    }
}

测试

		val money1 = Money(5)
        val money2 = Money(10)
        val money3 = money1 + money2
        println(money3.value)

打印结果
在这里插入图片描述
如果 Money 对象能直接和数字相加就更好了,我们可以实现这个功能,因为 Kotlin 允许我们对同一个运算符进行多重重载:

class Money(val value:Int){
    operator fun plus(money: Money):Money{
        val sum = value + money.value
        return Money(sum)
    }

    operator fun plus(int: Int):Money{
        val sum = value + int
        return Money(sum)
    }
}

使用

		val money1 = Money(5)
        val money2 = money1 + 10
        println(money2.value)

语法糖表达式和实际调用函数对照表

表达式 函数名
a + b plus
a - b minus
a * b times
a / b div
a % b rem,mod(弃用)
表达式 函数名
+a unaryPlus
-a unaryMinus
!a not
++a, a++ inc
--a, a-- dec
表达式 函数名
a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))
a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
a <= b a.compareTo(b) <= 0
表达式 函数名
a..b a.rangeTo(b)
a[b] a.get(b)
a[b] = c a.set(b,c)
a in b b.contains(a)

最后一个 a in b 表示判断 a 是否在 b 中,而 b.contains(a) 表示 b 是否包含 a
Kotlin 中 String 类就对 contains() 函数进行了重载,因此当我们判断 “hello” 中是否包含 “he” 可以这样写

if("hello".contains("he")){
}

借助重载的语法糖表达式,还可以这样写

if("he" in "hello"){    
}

我们之前使用过一个随机生成字符串长度的函数

fun getRandomLenthString(str:String):String{
        val n = (1..20).random()
        val builder = StringBuilder()
        repeat(n){
            builder.append(str)
        }
        return builder.toString()
    }

我们可以让一个字符串乘以一个数字来简化上面的方法,因此我们在 String.kt 中加入:

operator fun String.times(int:Int):String{
    val builder = StringBuilder()
    kotlin.repeat(int){
        builder.append(this)
    }
    return builder.toString()
}

使用

Log.d("MainActivity","This is content "*3)

另外必须说明的是,Kotlin 类中已经提供了一个用于将字符串重复 n 遍的 repeat() 函数了,因此 times() 函数可以进一步精简为

operator fun String.times(int:Int) = repeat(int)

因此刚才的 getRandomLenthString()函数可以使用这种写法了:

fun getRandomLenthString(str:String) = str * (1..20).random()
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐