Kotlin学习之旅(D4)-函数与Lambda表达式

Kotlin学习之旅-第四天

今天的主题是:函数与Lambda表达式

前言

Kotlin学习之旅(D1)-学习计划&基本语法

Kotlin学习之旅(D2)-基本语法

Kotlin学习之旅(D3)-类与继承

函数

Kotlin里面的函数其实在之前的学习中已经见过了,通过 fun 关键字来标识

fun double(x: Int): Int {
    return 2 * x
}

默认参数

除了一般的使用 x: Int 这种方式定义参数,我们也可以使用默认参数的方式,这种方式可以有效减少重载方法的数量

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {...}
  1. off是默认值为0的Int类型参数
  2. len是默认值为b.size的Int类型参数

命名参数

在Java里面,我们调用具有多个参数的方法,是无法直接看到每个参数的意思的,例如:

private void reformat(String str, Boolean normalizeCase, Boolean upperCaseFirstLetter, Boolean, divideByCamelHumps, Char wordSeparator){
    ...
}

// 调用方法
reformat(str, true, ture, ture, '_') 

在Kotlin里面,我们可以在调用的时候给参数加个名字,就像:

fun reformat(str: String,
             normalizeCase: Boolean = true,
             upperCaseFirstLetter: Boolean = true,
             divideByCamelHumps: Boolean = false,
             wordSeparator: Char = ' ') {
……
}

// 调用方法
reformat(str,
    normalizeCase = true,
    upperCaseFirstLetter = true,
    divideByCamelHumps = false,
    wordSeparator = '_'
)

这样代码的可读性更高,在多个参数的时候能清晰看到每个参数的作用

返回Unit的函数

前面写的几个方法都有返回值,那么如果要像Java里面一样返回void,在kotlin要怎么写呢?

fun printHello(name: String?): Unit {
    if (name != null)
        println("Hello ${name}")
    else
        println("Hi there!")
    // `return Unit` 或者 `return` 是可选的
}

通过 Unit 关键字表示返回 Unit类型,他的作用类似于Java里面的void,在Kotlin里面,Unit返回类型是可以省略的。

中缀表示法

标有 infix 关键字的函数也可以使用中缀表示法(忽略该调用的点与圆括号)调用。中缀函数必须满足以下要求:

infix fun Int.shl(x: Int): Int { …… }

// 用中缀表示法调用该函数
1 shl 2

// 等同于这样
1.shl(2)

中缀函数调用的优先级低于算术操作符、类型转换以及 rangeTo 操作符。 以下表达式是等价的:

  • 1 shl 2 + 31 shl (2 + 3)
  • 0 until n * 20 until (n * 2)
  • xs union ys as Set<*>xs union (ys as Set<*>)

另一方面,中缀函数调用的优先级高于布尔操作符 &&||is-in- 检测以及其他一些操作符。这些表达式也是等价的:

  • a && b xor ca && (b xor c)
  • a xor b in c(a xor b) in c

完整的优先级层次结构请参见其语法参考

Lambda 表达式

关于Lambda表达式这部分,从Java8就开始支持了,在实际开发中也会经常用到,但对我来说还是太抽象了,一直都不太理解,因此这一块我是参照官方文档来写的。如果有好的学习资料,欢迎大家留言~

lambda 表达式与匿名函数是“函数字面值”,即未声明的函数, 但立即做为表达式传递。考虑下面的例子:

max(strings, { a, b -> a.length < b.length })

函数 max 是一个高阶函数,它接受一个函数作为第二个参数。 其第二个参数是一个表达式,它本身是一个函数,即函数字面值,它等价于以下命名函数:

fun compare(a: String, b: String): Boolean = a.length < b.length

从上面的例子看来,其实Lambda就是一种函数的表达方式,这个函数还未声明,但是通过Lambda表达式可以直接调用,只要掌握了语法,就能很方便的写出来了。

Lambda 表达式语法

Lambda 表达式的完整语法形式如下:

val sum = { x: Int, y: Int -> x + y }

lambda 表达式总是括在花括号中, 完整语法形式的参数声明放在花括号内,并有可选的类型标注, 函数体跟在一个 -> 符号之后。如果推断出的该 lambda 的返回类型不是 Unit,那么该 lambda 主体中的最后一个(或可能是单个)表达式会视为返回值。

如果我们把所有可选标注都留下,看起来如下:

val sum: (Int, Int) -> Int = { x, y -> x + y }

把上面的官方文档说明翻译一下,就是:

1.lambda表达式总是括在花括号中
2.参数在->之前
3.函数在->之后

因此上面的例子翻译一下,就是:

1.{ x, y -> x + y } 为lambda表达式
2.(Int, Int) 为参数
3.Int = {...} 就是一个返回类型为Int的函数

it:单个参数的隐式名称

一个 lambda 表达式只有一个参数是很常见的。

如果编译器自己可以识别出签名,也可以不用声明唯一的参数并忽略 ->。 该参数会隐式声明为 it

ints.filter { it > 0 } // 这个字面值是“(it: Int) -> Boolean”类型的

几个Tips

  1. Lambda表达式可以传递给一个高阶函数当做参数

    fun <T, R> Collection<T>.fold(
        initial: R, 
        combine: (acc: R, nextElement: T) -> R
    ): R {
        var accumulator: R = initial
        for (element: T in this) {
            accumulator = combine(accumulator, element)
        }
        return accumulator
    }
    

    fold这个函数的第二个参数是 combine(R, T),同样是一个函数,他的返回值会作为fold的参数,那么flod就是一个高阶函数,而combine里面可以使用Lambda表达式~

  2. 如果函数的最后一个参数是一个函数,并且你传递一个 lambda 表达式作为相应的参数,你可以在圆括号之外指定它

    例如:

    val product = items.fold(1, { acc, e -> acc * e }) 
    => 
    val product = items.fold(1) { acc, e -> acc * e }
    
  3. 如果一个函数的参数只有一个,并且参数也是一个函数,那么可以省略圆括号

    例如:

    run ({ println("...") })
    =>
    run { println("...") }
    

总结

由于Kotlin里面Lambda表达式的使用还是很多的,所以建议大家多去看看其他的博客,因为我觉得官方文档对于没接触过Lambda的初学者来说还是太难懂了一点。

Day 4 - Learn Kotlin Trip, Completed.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值