IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin 学习 高阶函数 -> 正文阅读

[移动开发]Kotlin 学习 高阶函数

摘自第一行Android代码第3版

定义

如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个和函数,那么该函数就称为高阶函数

// 语法示例
(String,Int) -> Unit

-> 左边的部分就是用来声明函数接收什么参数,多个参数之间使用逗号隔开,如果不接受任何参数,写一对空括号就可以了。而->右边的部分用于声明该函数的返回值是什么类型,如果没有任何返回值就使用Unit,它大致相当于Java中的void

举个例子

fun example(func : (String , Int) -> Unit) {
	func("hello" , 123)
}		

来点实战

package com.example.broadcastbestpractice

/**
 * Create with IntelliJ IDEA.
 * Description:
 * User: coco
 * Date: 2022-01-07
 * Time: 10:56
 */


fun num1AndNum2(num1 : Int , num2 : Int , operation : (Int , Int) -> Int) : Int {
	val result = operation(num1 , num2)
	return result
}

fun plus(num1 : Int , num2 : Int) : Int {
	return num1 + num2
}

fun minus(num1 : Int , num2 : Int) : Int {
	return num1 - num2
}

fun main(){
	val num1 = 100
	val num2 = 80
	val result1 = num1AndNum2(num1,num2,::plus)
	val result2 = num1AndNum2(num1,num2,::minus)

	println("result1 is $result1")
	println("result2 is $result2")
}

使用lambda 替换

	val result1 = num1AndNum2(num1 , num2) { n1 , n2 -> n1 + n2 }
	val result2 = num1AndNum2(num1 , num2) { n1 , n2 -> n1 - n2 }

另一个例子

// 在函数类的前面加上ClassName就表示这个函数类型是定义在那个类当中
fun StringBuilder.build(block : StringBuilder.() -> Unit) : StringBuilder {
	block()
	return this
}

fun main() {
	val list = listOf("Apple" , "Banana" , "Orange" , "Pear" , "Grape")
	val result = StringBuilder().build {
		append("Start eating fruits.\n")
		for (fruit in list) {
			append(fruit).append("\n")
		}
		append("Ate all fruits.")
	}
	println(result.toString())
}

内联函数的使用

内联函数的用法非常简单,只需要在定义高阶函数时加上inline关键字的声明即可

inline fun num1AndNum2(num1 : Int , num2 : Int , operation : (Int , Int) -> Int) : Int {
	val result = operation(num1 , num2)
	return result
}

noline与crossinline

一个高阶函数中如果接收了两个或者更多个函数类型的参数,这时我们给的函数加上inline关键字,那么kotlin编译器会自动将所有引用的Lambda表达式全部进行内联

但是,如果我们只想内联其中的一个Lambda表达式该怎么办呢?这时就可以使用noinline关键字

inline fun inlineTest(block1 : () -> Unit , noinline block2 : () -> Unit) {
	
}

可以看到,这里使用inline关键字声明了inlineTest()函数,原来block1和block2这两个函数类参数所引用的Lambda表达式都会被内联。但是我们在block2参数的前面又加上了一个noinline关键字,那么现在就只会对block1参数所引起的Lambda表达式进行内联了,这就是noinline关键字的作用

为什么要用noinine取消内联功能

内联的函数类型参数在编译的时候会被进行代码替换,因此它没有真正的参数属性。非内联的函数参数类型可以自由地传递给其他任何函数,因为它就是一个真实的参数,而内联的函数类型参数只允许传递给另一个内联函数,这也是它最大的局限性

另外还有一个重要的区别,那就是内联函数所引用的Lambda表达式中可以使用return关键字来进行函数返回的,而非内联函数只能进行局部返回

package com.example.broadcastbestpractice

/**
 * Create with IntelliJ IDEA.
 * Description:
 * User: coco
 * Date: 2022-01-07
 * Time: 17:32
 */

fun printString(str : String , block : (String) -> Unit) {
	println("printString begin")
	block(str)
	println("printString end")
}

fun main() {
	println("main start")
	val str = ""
	printString(str) { s ->
		println("lambda start")
		if (s.isEmpty()) return@printString
		println(s)
		println("lambda end")
	}
}

输出如下

main start
printString begin
lambda start
printString end

Lambda表达式是不允许直接使用return关键字的,这里使用了return@printString的写法,表示进行局部返回,并且不在执行Lambda的剩余表达式

内联函数时的打印输出情况

inline fun printString(str : String , block : (String) -> Unit) {
	println("printString start")
	block(str)
	println("pinttString end")
}

fun main() {
	println("main start")
	val str = ""
	printString(str) { s ->
		println("lambda start")
		if (s.isEmpty()) return
		println(s)
		println("lambda end")
	}
}

输出如下

main start
printString start
lambda start

现在printString()函数已经变成了内联函数,我们就可以在Lambda表达式中使用return关键字。此时的return代表的是返回外层的调用函数,也就是main()函数

crossinline

将高阶函数直接声明成内联函数是一种良好的编程习惯,事实上,绝大多数高阶函数是可以直接声明成内联函数的,但是也有少部分例外的情况

inline fun runRunnable(block : () -> Unit){
	val runnable = Runnable{
		block()
	}
	runnable.run()
}

这段代码在没有加上inline关键字声明的时候绝对是可以工作的,但是在加上inline关键字之后就会提示错误
Can’t inline ‘block’ here: it may contain non-local returns. Add ‘crossinline’ modifier to parameter declaration ‘block’
借助crossinline 的声明,代码就可以郑航编译通过了

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-08 14:08:36  更:2022-01-08 14:08:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:00:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码