Kotlin学习笔记(三)-函数式编程

函数式编程

函数式编程(FP,Functional Programming),又称为泛函编程,是一种编程范式:一切皆是函数。函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数传入另一个函数,或者作为别的函数的返回值。

fun main(args: Array<String>) {
    val print = fun(x: Any) { print("  $x") }

    listOf(1, 2, 3).forEach(print) //   1  2  3
}

闭包就是把函数以及变量包起来,使得变量的生存周期延长。
闭包的组成:
1. 要执行的代码块{}。
2. 自由变量的左右域。

函数声明

/**
 * (Int)->Int 是函数类型声明,表示一个从Int映射到Int的函数。
 */
fun triple(double: (Int) -> Int): (Int) -> Int {
    return { x -> double(x) + x }
}

fun main(args: Array<String>) {
    val currentDouble = fun(x: Int): Int = x + x
    println(triple(currentDouble)(4)) // 12
}

扩展函数

通过“扩展”声明完成一个类的新功能扩展,而无需继承该类或使用设计模式(如装饰模式)。

/**
 * 拨打电话,扩展函数内部对应接收者对象(传过来的点符号的对象)
 */
fun Activity.toCall(mobile: String?) {
    if (TextUtils.isEmpty(mobile)) {
        return
    }
    val intent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:$mobile"))
    startActivity(intent)
}

函数参数

默认参数

函数参数可以有默认值,当省略相应的参数时使用默认值,减少函数重载。重写的方法(子类中)不能有默认值。

fun add(x: Int, y: Int = 0): Int {
    return x + y
}

fun main(args: Array<String>) {
    println(add(2)) //2
    println(add(2, 3)) //5
}

命名参数

参数有多个时候,不好理解,可以加上命名参数。

// ()中的startIndex 表示此参数的定义名称
val substring = name?.substring(startIndex = 1)

可变参数

参数的参数(通常是最后一个)可以用vararg修饰符标识。

fun main(args: Array<String>) {
    println(asList(2, 3, 4)) // [2, 3, 4]
}


fun <T> asList(vararg ts: T): List<T> {
    val result = ArrayList<T>()
    result += ts // for(t in ts){result.add(t)}
    return result
}

函数作用域

局部函数(嵌套函数)指一个函数在另一个函数内部。

fun add(x: Int = 0, y: Int = 0): Int {
    fun addMore(x: Int): Int {
        return 10 + x
    }

    return addMore(x) + y
}

fun main(args: Array<String>) {
    val add = add()
    println(add) // 10
}

成员函数是在类或者对象内部定义的函数。

高阶函数

高阶函数是将函数用作参数或返回值得函数。
函数类型声明的语法是:(x)->Y

fun isOdd(x: Int): Boolean {
    return x % 2 == 1
}

// :: 用来引用一个函数,省略了(this::isOdd)表示把一个方法当做一个参数,传递到另一个方法中进行使用
fun main(args: Array<String>) {
    val list = listOf(1, 2, 3)
    list.filter(::isOdd)
            .let { print(it) } // [1, 3]
}

匿名函数

 list.filter(fun(x: Int): Boolean {
        return x % 2 == 1
    }).let { println(it) } // [1, 3]

Lambda表达式

官网地址

list.filter({ it % 2 == 1 })
  • lambda表达式总是被大括号{}括着。
  • 其参数(若有)在->之前声明(参数类型可以省略)
  • 函数体(若有)在->之后

    1. 若入参lambda表达式是唯一函数,那么调用中圆括号可以省略。
list.filter({ it % 2 == 1 })
// 等价于
list.filter{ it % 2 == 1 }

Java中参数可以加括号,也可以省略括号,但是不能使用解构声明语法中的下划线(_)

txt.setOnClickListener((v)->{// do Something});
// 也可以使用:v->{}

Kotlin中参数加括号报错,解构声明语法

// txt.setOnClickListener((v)->{ }) // error
txt.setOnClickListener({ v -> /*do something*/ }) // 可以

// 以下就可以加括号
 val map = emptyMap<String, String>()
map.mapValues { (key, value) -> "$value!" }
map.mapValues { (entry) -> "$entry!" }
  1. it:单个参数的隐式名称

约定:如果函数字面值只有一个参数,那么它的声明(连同->)都可以省略。

list.map { it * 2 }
  1. 带接收者的函数字面值
class HTML{
    fun body(){
        println("HTML BODY")
    }
}

fun html(data:HTML.()->Unit):HTML{ // HTML.() 中的HTML是接收者类型
    val html  = HTML() // 创建接收者对象
    html.data() // 将该接收者对象传给改lambda
    return html
}
// 带接收者的函数字面值
fun main(args: Array<String>) {
    val sum = fun Int.(other: Int): Int = this + other
     println(1.sum(2)) // 3

    html { body() } // HTML BODY
}

内联函数

用inline修饰的函数,内联函数支持“具体化的类型参数”。参考Kotlin基础之内联函数

使用高阶函数会给运行时带来一些坏处:每个函数都是一个对象,捕获闭包(如:访问函数体内的变量),内存分配(函数对象或Class),虚拟调用引入的运行过载。 使用内联Lambda表达式在多数情况下可以消除这种过载,即通过编译预处理,省去函数调用的开销,提供运行效率,但是会以代码膨胀为代价。

inline fun <reified T: Activity> Activity.newIntent() {
    val intent = Intent(this, T::class.java)
    startActivity(intent)
}

尾递归

当一个函数用tailrec修饰符标记并满足所需的形式时,编译器会优化该递归,生成一个快速而高效的基于循环的版本。(优化后无堆栈溢出风险)
要符合tailrec修饰符的条件,函数必须将其自身调用作为他执行的最后一个操作。在递归调用后有更多代码时,不能使用尾递归,并且不能用在try/catch/finlly块中。

fun main(args: Array<String>) {
    println(findFixPoint(2.0)) //0.7390851332151607
}

tailrec fun findFixPoint(x: Double = 1.0): Double = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值