Kotlin inline关键字用法与作用详解
时间:2026-08-21 | 作者:风起客 | 阅读:0Kotlin 中的内联函数(Inline Function)是一种特殊的函数。与普通函数不同,编译器会在编译时将内联函数中的代码插入到调用处,避免函数调用的开销。它的作用和 C++ 中的内联函数类似,都是为了提高代码的执行效率。
定义内联函数
内联函数 的定义和普通函数类似,只是在函数名前添加 inline 关键字即可。
inline fun inlineFunction(block: () -> Unit) {
println(34;Inline function34;)
block()
}
从语法上看,调用方式和普通函数相似。
fun main() {
inlineFunction {
println(34;Hello, World!34;)
}
}
以上代码与下面的代码在执行效果上完全一致。
fun main() {
println(34;Inline function34;)
println(34;Hello, World!34;)
}
内联函数的return
kotlin 的 lambda 表达式return必须使用 return@scope 来指定返回的作用域。
由于内联函数的代码会被插入到调用处,所以内联函数可以使用 return,而不必须添加@限定符。比如:
fun main() {
inlineFunction {
println(34;Hello, World!34;)
return
}
}
而普通函数则必须使用 return@scope 来返回。比如:
fun main() {
normalFunction {
println(34;Hello, World!34;)
return@normalFunction
}
}
为什么?因为内联函数的代码会被插入到调用处。
所以上面的内联函数返回,就相当于:
fun main() {
println(34;Inline function34;)
println(34;Hello, World!34;)
// 这里的return是可以不添加限定符直接返回的
return
}
Kotlin 中的 return
从上面对内联函数的描述中,我们可以思考一个问题:什么时候return不需要添加@限定符呢?
- 当内联函数的lambda参数在顶层函数中被调用时,此时不添加限定符,return 就相当于直接返回顶层函数。
- 匿名函数中的return,也不需要添加@限定符。
内联函数在非内联函数中调用的时候,就需要使用@限定符来指定返回的作用域。比如:
fun main() {
normalFunction {
inlineFunction {
println(34;Hello, World!34;)
// 表示返回到inlineFunction
return@inlineFunction
// 或者返回到normalFunction
// return@normalFunction
}
}
inlineFunction {
println(34;Hello, World!34;)
// 直接返回到顶层函数,不需要添加@限定符
return
// 或者返回到normalFunction
// return@normalFunction
}
inlineFunction {
inlineFunction {
// 直接返回到顶层函数,可以不添加@限定符
return
// 或者返回到inlineFunction
// return@inlineFunction
}
}
normalFunction(fun ():Unit {
// 匿名函数中的return, 不需要添加@限定符
return
})
}
但是这里有一个问题:加了@限定符的return和不加@限定符的return有什么区别呢?
- 如果加了限定符,退出的只是当前作用域。
- 而不加限定符,退出的是整个函数。
Kotlin 中的 return 设计
那么,为什么Kotlin要设计成这样呢?为什么不设计的和Ja va一样,return返回的只是当前的作用域呢?目的有两个。
- 增加比Ja va代码更大的灵活性
- 避免使用内联函数时的逻辑混淆
1. 增加比Ja va代码更大的灵活性
Ja va代码中,lambda表达式中的return只能返回当前lambda作用域。
而Kotlin中的return可以返回任意作用域。这就增加了比Ja va代码更大的灵活性。
比如我们有一个需求:遍历一个列表,如果符合条件,终止遍历。我们先看看在Ja va中怎么实现。
public void breakOnCondition(List list, Predicate predicate) {
for (T t : list) {
if (predicate.test(t)) {
return;
}
}
}
public static void main(String[] args) {
List list = Arrays.asList(1, 2, 3, 4, 5);
breakOnCondition(list, i -> i == 3);
}
那么,在Kotlin中我们甚至不需要这样设计。
对于遍历场景,我们可以直接使用lambda表达式结合 return@scope 来终止当前遍历操作。
fun main() {
val list = listOf(1, 2, 3, 4, 5)
list.forEach {
if (it == 3) {
// 直接返回forEach循环
return@forEach
}
}
}
2. 避免使用内联函数时的逻辑混淆
如果可以不带有@限定符,那么用户在编写代码的时候,很难确定程序的行为。比如下面的代码:
fun normalFunction(block: () -> Unit) = block()
inline fun inlineFunction(block: () -> Unit) = block()
fun main() {
normalFunction {
// 这里是无法编译通过的,我们假定可以通过
return
}
// 会被执行
println(34;After normalFunction34;)
inlineFunction {
return
}
// 不会被执行
println(34;After inlineFunction34;)
}
假设上述代码正确且能编译通过。
在normalFunction函数中,其中的return结束的是该函数本身。
而在inlineFunction函数里,其return结束的却是main函数。这是因为inlineFunction函数中的代码会被插入到调用处,所以此处的return就相当于直接从main函数返回。
那么用户在编写代码的时候,就很容易混淆。
而如果非内联函数的lambda参数要求只能使用return@scope来返回,就会避免这种容易混淆的情况。
fun main() {
normalFunction {
return@normalFunction
}
// 会被执行
println(34;After normalFunction34;)
inlineFunction {
return@inlineFunction
}
// 会被执行
println(34;After inlineFunction34;)
inlineFunction {
return
}
// 不会被执行
println(34;After inlineFunction34;)
}
reified 类型参数
reified 类型参数是Kotlin中一种特殊的类型参数,它可以在运行时获取到类型信息。
还记得Ja va中怎么获取泛型类型吗?
public T parseObj(String json, Class clazz) {
return new Gson().fromJson(json, clazz);
}
在Ja va中,我们必须添加 Class clazz 参数来指定泛型类型。
否则,我们无法在运行时获取到泛型类型。因为Ja va代码中如果没有和泛型相关的对象传入进来的话,是无法在运行时获取到泛型类型的。
但是在Kotlin的内联函数中,提供了reified 类型参数。
它可以在函数不提供参数信息情况下,获取到泛型类型。比如下面的代码:
inline fun parseObj(json: String): T {
return new Gson().fromJson(json, T::class.ja va)
}
有了它,我们在函数里可以直接用T::class.ja va获取泛型类型,再也不需要传入Class clazz参数了。
MybatisPlus提供了KtQueryChainWrapper类,借助这个类,我们可以通过lambda的方式来构建查询参数。
@Autowired
private lateinit var baseMapper: BaseMapper
val chain = KtQueryChainWrapper(baseMapper, entityClass=Config::class.ja va)
val config = chain.eq(Config::name, 34;test34;).one()
为了方便,我们可以为 BaseMapper 添加一个扩展方法,来获取 KtQueryChainWrapper 类。
fun BaseMapper.query(): KtQueryChainWrapper {
// 很要命的是 mybatisplus 要求必须填写 entityClass 参数,否则会报错
return KtQueryChainWrapper(baseMapper = this, entityClass = entityClass())
}
// 使用的时候就会很方便
val config = baseMapper.query().eq(Config::name, 34;test34;).one()
但是,怎么获取 entityClass 呢?
如果没有 reified 关键字,我们只能通过反射来获取。比如下面的代码:
private fun BaseMapper.entityClass(): Class {
val searchEntityClass = ja vaClass.searchEntityClass()
if (searchEntityClass != null) {
return searchEntityClass
}
throw IllegalArgumentException(34;无法获取实体类34;)
}
private fun Class<*>.searchEntityClass(): Class {
for (type in genericInterfaces) {
if (type is ParameterizedType) {
if (type.rawType == BaseMapper::class.ja va) {
return type.actualTypeArguments[0] as Class
}
} else {
if (type is Class<*>) {
return type.searchEntityClass()
}
}
}
return null
}
这时候如果我们使用 内联函数 + reified 类型参数,就可以避免使用反射来获取泛型类型。比如下面的代码:
inline fun BaseMapper.query(): KtQueryChainWrapper {
// 在使用了reified 类型参数后,就可以直接使用 T::class.ja va 来获取泛型类型
return KtQueryChainWrapper(baseMapper = this, entityClass = T::class.ja va)
}
可以看到,使用了 reified 类型参数后,就可以直接使用 T::class.ja va 来获取泛型类型,而不需要通过反射来获取。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 迅捷路由器怎么调信号最强,设置时要注意什么?
- 时间:2026-08-27
-
- vivo浏览器怎么卸不掉?原因和解决方法在这里
- 时间:2026-08-27
-
- OPPO R11s黑屏了,怎么强制恢复出厂设置?
- 时间:2026-08-27
-
- 飞利浦显示器包装盒有生产日期和保修期吗?怎么看?
- 时间:2026-08-27
-
- 联想新平板开机必须联网吗?怎么做?
- 时间:2026-08-27
-
- 平板横竖屏切换设置与问题解决
- 时间:2026-08-27
-
- 移动电源容量怎么测?要准备哪些工具?
- 时间:2026-08-27
-
- 荣耀90 Pro防水吗?防水级别多少?怎么用才安全
- 时间:2026-08-27
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
