当前位置: 首页 > news >正文

Kotlin 函数

文章目录

  • 函数的定义
  • 函数的返回值
  • 参数默认值 & 调用时参数指定
  • 函数作用域
  • Lambda 表达式
  • 匿名函数
  • 内联函数
  • 扩展函数
  • 中缀函数
  • 递归函数 & 尾递归函数

函数的定义

函数可以理解成一个小小的加工厂,给入特定的原材料,它就会给出特定的产品。

fun [接收者类型.][函数名]([参数名: 参数类型], ...)[:返回值类型] [函数体]

我们只需要写一次,便可以反复使用:

fun greeting(name: String) {println("Hello $name!")
}fun main() {greeting("Today")greeting("Kotlin")
}
Hello Today
Hello Kotlin

Note:调用函数时,函数参数有多个,且未指定参数名,需要按参数顺序传入参数。

函数的返回值

函数都会有返回值,默认的返回值是Unit(无论何时,Unit都是唯一的一个值(单例),不可以被实例化),可以省略不写:

fun greeting(name: String): Unit {println("Hello $name!")return Unit// return
}

函数的返回值会给到调用处,也就是说下方的getResult()就代表了默认返回值Unit。我们可以直接打印出返回值,或者将其赋值给变量:

fun getResult() {}fun main() {val result: Unit = getResult()println(result)print(getResult())
}
kotlin.Unit
kotlin.Unit

我们也可以指定返回其他类型:

fun plus1(old: Int): Int {return old + 1
}fun main() {val new = plus1(0)print(new)
}
1

甚至可以返回一个函数(这可能有点超纲了,看不懂可以先不理,请参考下方Lambda 表达式匿名函数):
这里的getFun返回了一个无参数的、返回值为String类型的函数。

fun getFun(): () -> String {return { "Hello World" }
}fun main() {val greet = getFun()val msg = greet()print(msg)
}
Hello World

Note:Kotlin 中函数类型的书写格式是(参数名和冒号:可省略):

([参数名: 参数类型], ...) -> [返回值类型]

fun main() {val myFun: (Int) -> Int = {it + 1}print(myFun(0))
}
1

与之类似的写法是:

fun main() {fun myFun(int: Int): Int {return int + 1}print(myFun(0))
}

或者

fun main() {val myFun = fun(int: Int): Int {return int + 1}print(myFun(0))
}

一个函数可以作为另一个函数的参数:

fun caller(block: () -> Unit) {// 调用 block 函数block()
}fun main() {// 调用 caller 函数,传入 lambdacaller({ print("Hello World") })
}
Hello World

如果函数体可以用一句表达式表示,则可以直接用等号=,返回值类型也可以省略:

fun getYear() = 2024fun getInt(boolean: Boolean) = if (boolean) 1 else 0fun getBoolean(int: Int) = when(int) {0 -> falseelse -> true
}fun main() {println(getYear())println(getInt(true))print(getBoolean(1))
}
2024
1
true

参数默认值 & 调用时参数指定

当某个参数为可选时,可以为参数赋默认值(我们一般将可选参数放于必要参数之后,但这不是硬性要求):

fun greet(otherParams: Int, name: String = "Kotlin") {print("Hello $name")
}fun main() {greet(0)
}
Hello Kotlin

我们也可以在调用时指定参数传值(下方的exampleParam):

fun greet(name: String, exampleParam: Int = 0, exampleParam1: Int = 1) {println("Hello $name")print("exampleParam: $exampleParam, exampleParam1: $exampleParam1")
}fun main() {greet("Kotlin", exampleParam = 2)
}
Hello Kotlin
exampleParam: 2, exampleParam1: 1

函数作用域

在函数中定义的变量、函数,在函数外无法访问:

fun main() {fun funScope() {val name = "Kotlin"fun innerFun() {}}// print(name) 无法访问// innerFun() 无法访问
}

函数内可以访问函数外定义的变量、函数:

fun main() {val name = "Kotlin"fun outerFun() { print("Outer Fun") }fun funScope() {// 可以调用外部内容println(name)outerFun()}funScope() // 我们需要调用函数才能看到其运行结果
}
Kotlin
Outer Fun

Lambda 表达式

我们已经不止一次提到它了,它的写法是这样的:

// 匿名函数
{ [参数名: 参数类型], ... ->[函数体]
}

不指明类型的函数类型变量,它的类型会是() -> Unit
当 lambda 的参数只有一个时,这个参数可以省略不写,通过it指定:

fun main() {val myLambda: (String) -> Unit = {print("Hello $it")}
}

当 lambda 作为函数的最后一个参数进行传递时,可以将花括号{}移到调用的小括号()外面,称为尾部 lambda(trailing lambda):

fun caller(name: String, block: () -> Unit) {}fun main() {caller("Kotlin", { print("不移出小括号") })caller("Kotlin") {print("移出小括号")}
}

若没有return,lambda 表达式的最后一个值会作为函数的返回值:

fun caller(block: () -> String) {print(block())
}fun main() {caller { "ABC" }
}
ABC

匿名函数

匿名函数无需写函数名(lambda 表达式也是匿名函数):

fun([参数名: 参数类型], ...)[: 返回值类型] [函数体]
fun main() {val mySingleLineFun = fun() = 1val myFun = fun(name: String) {print("Hello $name")}println(mySingleLineFun())myFun("Kotlin")
}
1
Hello Kotlin

内联函数

内联函数可以将参数中 lambda 表达式的代码插入到函数调用处,提高性能。声明内联函数只需要在fun前加inline。内联函数会使编译后的代码更加庞大,我们必须在最合适的时候使用它(错误使用时 IDEA 会警告)。用得比较多的场景是函数有参数为函数类型。

inline fun caller(block: () -> String) {print(block())
}fun main() {caller { "ABC" }
}

printprintln因为参数类型为Any,可能为函数类型。可以看到 JVM 平台它们的实现(actual)其实是 Java 的System.out.printSystem.out.println(可以通过按住Ctrl键,鼠标点击函数,跳转到函数声明处):

// 
@kotlin.internal.InlineOnly
public actual inline fun print(message: Any?) {System.out.print(message)
}...@kotlin.internal.InlineOnly
public actual inline fun println(message: Any?) {System.out.println(message)
}

如果不希望某一函数类型的参数被内联时,可以将其标记为noinline

inline fun caller(noinline noinlineBlock: () -> Unit
) {}

当内联函数(下方call)可内联的函数类型参数(下方block)被传入的内联函数(下方noinlineBlock)调用时,需要标记为crossinline

inline fun caller(noinline noinlineBlock: () -> Unit
) {}inline fun call(crossinline block: () -> Unit) {caller{ block() }
}

扩展函数

还记得我们最开始说的函数类型声明吗?这里有一个接收者

fun [接收者类型.][函数名]([参数名: 参数类型], ...)[:返回值类型] [函数体]

我们可以通过声明接收者,将某一函数定义为接收者所拥有的函数,称为其扩展函数。
这可能有点难以理解,因为我们还没有讲到,我在这里做一个简单的解释:

  • 我们定义了一个以Int作为接收者的函数add用于对Int类型数值加上(+)值other
  • 在该函数中,this会指代接收者Int类型,例如这里调用int.add,在addthis + other相当于0 + 3,结果为3,会返回到调用处。
fun Int.add(other: Int) = this + otherfun main() {val int = 0print(int.add(3))
}
3

中缀函数

我们可以通过 infix 关键字将一个函数声明为中缀函数,我们还是以上方扩展函数为例(因为中缀函数必须为扩展函数成员方法,而且有且仅有一个参数)。
可以看到运行结果其实是一样的,只是在调用时可以将int.add(3)写成int add 3,函数名作为类似运算符的存在。

infix fun Int.add(other: Int) = this + otherfun main() {val int = 0println(int.add(3))print(int add 3)
}
3
3

递归函数 & 尾递归函数

递归就是一个函数自己调用自己。

fun myFun() {myFun()
}

我们细想一下就会发现这样是不可取的,myFun调用了myFun,而被调用的myFun又调了myFun······看来一时半会是停不了了。
如果我们给递归加上条件,当start == end时才递归,它就能够停下来:

fun countTo(end: Int, start: Int = 0) {println("现在是: $start")if (start == end) returnelse countTo(end, start + 1)
}fun main() {countTo(5)
}
现在是: 0
现在是: 1
现在是: 2
现在是: 3
现在是: 4
现在是: 5

其实就有点像循环:

fun main() {var start = 0val end = 5while (start <= end) {println("现在是: $start")start ++}
}

当递归调用在末尾时,可以在fun前加tailrec,使函数成为尾递归函数(tail recursive functions),编译器会优化该递归,生成一个循环(参考示例)。

相关文章:

Kotlin 函数

文章目录 函数的定义函数的返回值参数默认值 & 调用时参数指定函数作用域Lambda 表达式匿名函数内联函数扩展函数中缀函数递归函数 & 尾递归函数 函数的定义 函数可以理解成一个小小的加工厂&#xff0c;给入特定的原材料&#xff0c;它就会给出特定的产品。 fun [接…...

动态路由协议实验——RIP

动态路由协议实验——RIP 什么是RIP ​ RIP(Routing Information Protocol,路由信息协议&#xff09;是一种内部网关协议&#xff08;IGP&#xff09;&#xff0c;是一种动态路由选择协议&#xff0c;用于自治系统&#xff08;AS&#xff09;内的路由信息的传递。RIP协议基于…...

数据结构 | 二叉树(基本概念、性质、遍历、C代码实现)

1.树的基本概念 树是一种 非线性 的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#xff0c;称为根…...

很多Oracle中的SQL语句在EF中写不出来

很多复杂的Oracle SQL语句在Entity Framework&#xff08;EF&#xff09;中很难直接表达出来。虽然EF提供了一种方便的方式来使用C#代码查询和操作数据库&#xff0c;但它在处理某些复杂的SQL特性和优化时可能会有局限性。 以下是一些在EF中可能难以直接实现的Oracle SQL功能和…...

浏览器打开PHP文件弹出下载而不是运行代码

说明 使用phpstudy&#xff0c;极少会出现这种情况。 这里主要是帮助大家理解&#xff0c;为什么上传的木马不运行。 问题原因 首先需要理解&#xff0c;访问PHP文件弹出下载&#xff0c;说明服务端的容器&#xff08;比如Apache或者Nginx&#xff09;把文件当成了一个普通二…...

安卓自定义UI组件开发流程

安卓自定义ui组件开发流程 开发安卓自定义UI组件的流程大致可以分为以下几个步骤&#xff1a; 确定需求和设计&#xff1a; 确定需要自定义的UI组件的功能和外观。设计组件的交互逻辑和视觉效果。 创建自定义组件类&#xff1a; 创建一个新的Java类&#xff0c;继承自View、V…...

【LINUX】LINUX基础(目录结构、基本权限、基本命令)

文章目录 LINUX的目录结构LINUX的基本权限LINUX基本命令 LINUX的目录结构 /&#xff1a;表示根目录bin&#xff1a;存放二进制可执行文件(命令ls、cat、mkdir等)boot&#xff1a;存放系统引导文件dev&#xff1a;存放设备文件etc&#xff1a;存放系统配置文件home&#xff1a;…...

Aigtek功率放大器的主要性能要求有哪些

功率放大器是电子系统中的重要组件&#xff0c;用于将低功率信号放大到高功率水平。功率放大器的性能直接影响到信号的放大质量和系统的整体性能。下面西安安泰将介绍功率放大器的主要性能要求。 增益&#xff1a;功率放大器应当具有足够的增益&#xff0c;即将输入信号的幅度放…...

2024.5.29晚训参考代码

因为本套题没有BFS例题&#xff0c;所以我先把BFS模板放着 #include<bits/stdc.h> using namespace std; int n,m;//n*m的棋盘 int dis[402][402]; bool vis[402][402]; int X[]{-2,-2,-1,-1,1,1,2,2};//偏移量的表 int Y[]{-1,1,-2,2,-2,2,-1,1};//定义一个数组&…...

【计算机网络】——概述(图文并茂)

概述 一.信息时代的计算机网络二.互联网概述1.网络&#xff0c;互连网&#xff0c;互联网&#xff08;因特网&#xff09;1.网络2.互连网3.互联网&#xff08;因特网&#xff09; 2.互联网简介1.互联网发展的三个阶段2.互联网服务提供者&#xff08;ISP&#xff09;3.互联网的组…...

C语言多个源程序编译的CMakeList文件编写/源程序生成动态库

1.编译多个源程序时CMakeLists文件编写 1.若源程序目录结构如下&#xff1a; main.cpp中include“LCD_2inch4.h”头文件&#xff0c;而LCD_2inch4.h中include其它源程序&#xff0c;则CmakeLists.txt文件可为如下&#xff1a; # 设置项目名称 cmake_minimum_required(VERSI…...

C# list集合

一、list集合基本使用 1.添加元素 ① 单个元素添加 List<int> list new List<int>();for (int i 0; i < 3; i){list.Add(i);}//输出&#xff1a;0,1,2 ②初始化时添加元素 List<int> list2 new List<int> { 1, 2, 3 };//输出&#xff1a;0,1…...

****三次握手和四次挥手

一、三次握手 1.简要描述TCP三次握手的过程 第一次握手&#xff0c;客户端发送SYN包到服务器&#xff1b; 第二次握手&#xff0c;服务器收到SYN包&#xff0c;回复一个SYNACK包&#xff1b; 第三次握手&#xff0c;客户端收到服务器的SYNACK包后&#xff0c;回复一个ACK包…...

开发语言Java+前端框架Vue+后端框架SpringBoot开发的ADR药物不良反应监测系统源码 系统有哪些优势?

开发语言Java前端框架Vue后端框架SpringBoot开发的ADR药物不良反应监测系统源码 系统有哪些优势&#xff1f; ADR药物不良反应监测系统具有多个显著的优势&#xff0c;这些优势主要体现在以下几个方面&#xff1a; 一、提高监测效率与准确性&#xff1a; 通过自动化的数据收集…...

问题排查|记录一次基于mymuduo库开发的服务器错误排查(段错误--Segmentation fault (core dumped))

问题记录&#xff1a; 在刚完成mymuduo库之后&#xff0c;写了一个简单的测试服务器&#xff0c; 但是在服务器运行后直接报错&#xff1a; cherryhcss-ecs-4995:~/mymuduo/example$ ./testserver Segmentation fault (core dumped)出现多错误这通常意味着程序试图访问其内存空…...

Mysql常用操作DQL数据库、表操作:

DQL是指MySQL数据库中的数据查询语言&#xff08;Data Query Language&#xff09;。它是用来从数据库中检索所需数据的语言。DQL允许用户通过指定查询条件和筛选条件来检索数据库中的数据&#xff0c;并以所需的方式来显示结果。DQL语句可以用于从单个表中查询数据&#xff0c…...

标题:Go语言中的YAML魔法:轻松配置你的环境

摘要&#xff1a; 本文将介绍如何在Go语言项目中使用YAML文件来管理配置&#xff0c;包括如何读取YAML文件以及如何在代码中解析和使用这些配置。 正文&#xff1a; 在编程世界中&#xff0c;配置管理是每个项目都必须面对的问题。对于Go语言项目来说&#xff0c;YAML文件是一…...

STM32高级控制定时器之输入捕获模式

目录 概述 1 输入捕获模式 1.1 原理介绍 1.2 实现步骤 1.3 发生输入捕获流程 2 使用STM32Cube配置工程 2.1 软件环境 2.2 配置参数 2.3 生成项目文件 3 功能实现 3.1 PWM调制占空比函数 3.2 应用函数库 4 测试 4.1 功能框图 4.2 运行结果 源代码下载地址&#xf…...

使用 Vue 3 和 qrcode.js 开发二维码显示组件

二维码在现代应用中广泛使用&#xff0c;例如支付、身份验证、链接分享等。本文将介绍如何使用 Vue 3 和 qrcode.js 库来创建一个灵活的二维码显示组件&#xff0c;并展示如何在应用中使用它。 1. 安装必要的依赖 首先&#xff0c;我们需要安装 Vue 3 和 qrcode.js。如果你还…...

LabVIEW异步编程概述

LabVIEW异步编程是一种在图形化编程环境中处理并行任务的方法。通过异步执行&#xff0c;可以提高程序的响应速度和资源利用效率&#xff0c;使得多个任务可以独立进行而不互相干扰。 原理 LabVIEW异步编程的核心在于使用异步调用节点&#xff08;Asynchronous Call By Refer…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...