Kotlin:函数与函数式编程(五)

函数式编程语言最重要的基础是lambda演算,而且lambda演算的函数可以传入函数参数,也可以返回一个函数。函数式编程(简称FP)是一种编程范式。
函数式编程与命令式编程最大的不同是:函数式编程的焦点在于数据的映射,命令式编程的焦点是解决问题的步骤。函数式编程不仅仅指的是某一种语言,更重要的是一种编程思想,解决问题的思考方式,也称面向函数编程。

1、函数式编程简介
函数式编程是关于不变性和函数组合的编程范式。函数式编程有如下特性:
(1)一等函数支持:函数也是一种数据类型,可以作为参数传入另一个函数中,同时函数也可以返回一个函数。
(2)纯函数和不变性:纯函数指的是没有副作用的函数(函数不去改变外部的数据状态)。例如,一个编译器就是一个广义上的纯函数。在函数式编程中,倾向于使用纯函数编程。正因为纯函数不会去修改数据,同时又使用不可变的数据,所以程序不会取修改一个已经存在的数据结构,而是根据一定的映射逻辑创建一份新的数据。函数式编程是转换数据而非修改原始数据。
(3)函数的组合:在面向对象编程中是通过对象之间发送消息来构建程序逻辑的;而在函数式编程中是通过不同函数组合来构建程序逻辑的。

2、声明函数

// 函数声明
fun sum(a : Int,b : Int) : Int {
    return a + b
}
println("函数声明:sum = " + sum(3,7))
// 输出:I/System.out: 函数声明:sum = 10

fun:声明函数的关键字
sum:函数名
a : Int,b : Int:函数参数列表
: Int:函数返回值
return a + b:函数体

函数也可以作为变量来使用,声明一个函数类型的变量sum:

// 声明一个函数类型的变量sum
val sum = fun(a : Int, b : Int) : Int {
      return a + b
}
println("声明一个函数类型的变量:sum = " + sum(30,79))

可以看出这个函数变量sum的类型是(Int,Int)-> Int。这个带箭头"->"的表达式就是一个函数类型,表示一个输入两个Int类型值,输出一个Int类型值得函数。

3、Lambda表达式
一个例子:

 // Lambda表达式
 val intList = listOf<Int>(1,2,3,4,5,6,7,8,9,0)
 println("列表中奇数的数字有 :" + intList.filter( { it % 2 == 1}))
 // 因为filter函数只有一个参数,所以也可以去掉(),既intList.filter{ it % 2 == 1}
 // 输出
 I/System.out: 列表中奇数的数字有 :[1, 3, 5, 7, 9]

这里的filter()函数的入参{ it % 2 == 1}就是一段Lambda表达式。Lambda表达式需要用{}符号。
以上是一种简写的Lambda表达式,完整的Lambda表达式是:

 { it -> it % 2 == 1}

拆开下如下:

// 拆开Lambda表达式
val isOdd = {it : Int -> it % 2 == 1}
println("列表中奇数的数字有 :" + intList.filter( isOdd))

4、高阶函数
高阶函数就是将 函数 作为 参数 或 返回值的函数。
lambda表达式中filter函数的参数是一个函数,类型为predicate: (T) -> Boolean,其原型为:
所以 filter为高阶函数,下面的例子,查看列表中字符串,列出其长度为偶数的字符串。

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}
 // 高阶函数
 val f = fun(x : Int) = x % 2 == 0  // 判断输入的int是否为奇数。 函数声明:输入参数为int类型,函数体:x % 2 == 0
 val g = fun(s : String) = s.length // 获取输入的字符串的长度。 函数声明: 输入参数为String类型,函数体: s.length

 // 声明 函数h,两个参数,分别为函数g 和 函数f。输出为(String)-> Boolean类型。函数体:return { f(g(it)) }
 // 函数类型参数:g 函数名,(String)函数g输入类型,Int 函数g的输出类型
 val h = fun(g : (String) -> Int, f : (Int) -> Boolean) : (String)-> Boolean {
      return { f(g(it)) }
 }

 // 函数调用
 var list = listOf("udydgdh","hfidhd","gfhfjdhggdudud","fhfiahihfiaifagif","gfys")
 
 // h(g,f)类似于数学公式。
 println("列表中,长度为偶数的字符串有:" + list.filter (h(g,f)))

 // 输出:
 I/System.out: 列表中,长度为偶数的字符串有:[hfidhd, gfhfjdhggdudud, gfys]

注意:在函数体的代码return { f(g(it)) }中,{}代表这是一个Lambda表达式,返回的是一个(String)-> Boolean 函数类型。如果没有{},那么返回值就是一个布尔类型Boolean。

5、Kotlin 中的特殊函数
本节介绍kotlin中的run() apply() let() also() with() 这5个特殊的函数。使用的测试代码如下:

 fun myFun() : String {
        println("执行了myfun函数")
        return "这是myfun函数的返回值"
 }

(1)run()函数
定义如下:

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

重点看最后一行block(),其实就是调用传入的block参数,一般情况下是一个Lambda函数。测试代码如下:

fun testRunFun() {
        println("ceshi run1")
        println(myFun())       // 直接在代码行调用函数
        println("ceshi run2")
        run({myFun()})         // 使用run()函数调用myfun()函数
        println("ceshi run3")
        run {myFun()}          // run()函数的()可以省略
        println("ceshi run4")
        run {println("A")}     // 等价于println("A")
    }

直接结果:
在这里插入图片描述

(2)apply()函数
函数定义如下:

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

重点看最后两行代码,显示调用了block()函数,然后返回当前的调用者对象this。意思是执行完block()代码块逻辑后,再次返回当前的调用者对象。测试代码:

fun testApply() {
        // 普通写法
        val list = mutableListOf<String>()
        list.add("A")
        list.add("B")
        list.add("C")
        println("普通写法 list = $list")
        println(list)

        // 使用apply()
        val a = ArrayList<String>().apply { // 调用apply函数
            add("D")
            add("E")
            add("F")
            println("使用apply()函数写法 this = $this")
        }

        println(a)
        // 等价于
        a.let { println(it) }
    }

测试结果:
在这里插入图片描述
(3)let()函数
函数定义如下:

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

看最后一行代码block(this),意思是把当前调用对象作为参数传入block()代码块中。测试代码如下:

fun testLet() {
        1.let{ println(it)}        // 输出1,其中it就是调用者1
        "ABC".let { println(it) }  // 输出“ABC”,其中it就是调用者ABC
        myFun().let { println(it) } // 执行完myFun()函数后,返回值传给let()函数
    }

测试结果:
在这里插入图片描述
(4)also()函数
函数定义:

@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

最后两句,首先是调用了block(this),类似let()函数的逻辑,但是最后返回值是this,也就是当前的调用者。测试代码:

fun testAlso() {
        var a = "ABC".also { println(it) }
        println("a = $a")

        a.let { println(it) }
    }

测试结果:
在这里插入图片描述
(5)with()函数
函数定义如下:

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

最后两行,首先是调用了block(this),类似let()函数的逻辑,但是最后返回的值是this,也就是当前的调用者。测试代码如下:

fun testWith() {
        // 普通写法
        val list = mutableListOf<String>()
        list.add("A")
        list.add("B")
        list.add("C")
        println("普通写法 list = $list")
        println(list)

        // 使用with()函数
        with(ArrayList<String>()) {
            add("D")
            add("E")
            add("F")
            println("使用with函数写法 this = $this")
        }.let { println(it) } // kotlin.Unit
    }

测试结果:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值