KotlinInline关键字

Kotlin 中的内联函数(Inline Function)是一种特殊的函数,与普通函数不同, 编译器会在编译时将内联函数中的代码插入到调用处, 避免函数调用的开销。它的作用和 C++ 中的内联函数类似,都是为了提高代码的执行效率。

定义内联函数

内联函数 的定义和普通函数类似, 只是在函数名前添加 inline 关键字即可。

inline fun inlineFunction(block: () -> Unit) {
    println("Inline function")
    block()
}

从语法上看,调用方式和普通函数相似

fun main() {
    inlineFunction {
        println("Hello, World!")
    }
}

以上代码与下面的代码在执行效果上完全一致

fun main() {
    println("Inline function")
    println("Hello, World!")
}

内联函数的return

kotlinlambda 表达式return必须使用 return@scope 来指定返回的作用域,由于内联函数的代码会被插入到调用处,所以内联函数可以使用 return 而不必须添加@限定符。比如

fun main() {
    inlineFunction {
        println("Hello, World!")
        return
    }
}

而普通函数则必须使用 return@scope 来返回, 比如

fun main() {
    normalFunction {
        println("Hello, World!")
        return@normalFunction
    }
}

为什么?因为内联函数的代码会被插入到调用处,所以上面的内联函数返回就相当于

fun main() {
    println("Inline function")
    println("Hello, World!")
    // 这里的return是可以不添加限定符直接返回的
    return
}

Kotlin 中的 return

从上面对内联函数的描述中,我们可以思考一个问题:什么时候return不需要添加@限定符呢?

  1. 当内联函数的lambda参数在顶层函数中被调用时,此时不添加限定符,return 就相当于直接返回顶层函数。
  2. 匿名函数中的return, 也不需要添加@限定符

内联函数在非内联函数中调用的时候, 就需要使用@限定符来指定返回的作用域。比如

fun main() {
    normalFunction {
        inlineFunction {
            println("Hello, World!")
            // 表示返回到inlineFunction
            return@inlineFunction
            
            // 或者返回到normalFunction
            // return@normalFunction
        }
    }
    inlineFunction {
        println("Hello, World!")
        // 直接返回到顶层函数,不需要添加@限定符
        return
        
        // 或者返回到normalFunction
        // return@normalFunction
    }

    inlineFunction {
        inlineFunction {
            // 直接返回到顶层函数,可以不添加@限定符
            return
            
            // 或者返回到inlineFunction
            // return@inlineFunction
        }
    }

    normalFunction(fun ():Unit {
        // 匿名函数中的return, 不需要添加@限定符
        return
    })
}

但是这里有一个问题,加了@限定符的return和不加@限定符的return有什么区别呢?

  • 如果加了限定符,退出的只是当前作用域
  • 而不加限定符,退出的是整个函数

Kotlin 中的 return 设计

那么,为什么Kotlin要设计成这样呢?为什么不设计的和Java一样,return返回的只是当前的作用域呢?目的有两个

  1. 增加比Java代码更大的灵活性
  2. 避免使用内联函数时的逻辑混淆
1. 增加比Java代码更大的灵活性

Java代码中,lambda表达式中的return只能返回当前lambda作用域,而Kotlin中的return可以返回任意作用域。这就增加了比Java代码更大的灵活性。

比如我们有一个需求,遍历一个列表,如果符合条件,终止遍历,我们看看在Java中怎么实现

public <T> void breakOnCondition(List<T> list, Predicate<T> predicate) {
    for (T t : list) {
        if (predicate.test(t)) {
            return;
        }
    }
}

public static void main(String[] args) {
    List<Integer> 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("After normalFunction")
    inlineFunction {
        return
    }
    // 不会被执行
    println("After inlineFunction")
}

假设上面的代码正确,并且可以编译通过。
这里的 normalFunction 中的return,结束的是 normalFunction 函数。
而 inlineFunction 中的return,结束的却是main函数,因为inlineFunction 中的代码会被插入到调用处,所以inlineFunction 中的return 就相当于直接返回main函数。

那么用户在编写代码的时候,就很容易混淆。

而如果非内联函数的lambda参数要求只能使用return@scope来返回,就会避免这种容易混淆的情况。

fun main() {
    normalFunction {
        return@normalFunction
    }
    // 会被执行
    println("After normalFunction")

    inlineFunction {
        return@inlineFunction
    }
    // 会被执行
    println("After inlineFunction")

    inlineFunction {
        return
    }
    // 不会被执行
    println("After inlineFunction")
}

reified 类型参数

reified 类型参数是Kotlin中一种特殊的类型参数,它可以在运行时获取到类型信息。还记得Java中怎么获取泛型类型吗?

public <T> T parseObj(String json, Class<T> clazz) {
    return new Gson().fromJson(json, clazz);
}

在Java中,我们必须添加 Class<T> clazz 参数来指定泛型类型。否则,我们无法在运行时获取到泛型类型。因为Java代码中如果没有和泛型相关的对象传入进来的话,是无法在运行时获取到泛型类型的。

但是在Kotlin的内联函数中,提供了reified 类型参数,它可以在函数不提供参数信息情况下,获取到泛型类型。比如下面的代码

inline fun <reified T> parseObj(json: String): T {
    return new Gson().fromJson(json, T::class.java)
}

想象一下这个参数可以给我们带来多大的便利性,我们可以直接在函数中使用T::class.java来获取到泛型类型,而不需要传入Class<T> clazz 参数。
MybatisPlus 提供了 KtQueryChainWrapper 类,通过这个类,可以通过lambda的方式构建查询参数。

@Autowired
private lateinit var baseMapper: BaseMapper<Config>

val chain = KtQueryChainWrapper(baseMapper, entityClass=Config::class.java)
val config = chain.eq(Config::name, "test").one()

为了方便,我们可以为 BaseMapper 添加一个扩展方法,来获取 KtQueryChainWrapper 类。

fun <T : Any> BaseMapper<T>.query(): KtQueryChainWrapper<T> {
    // 很要命的是 mybatisplus 要求必须填写 entityClass 参数,否则会报错
    return KtQueryChainWrapper(baseMapper = this, entityClass = entityClass())  
}

// 使用的时候就会很方便
val config = baseMapper.query().eq(Config::name, "test").one()

但是,怎么获取 entityClass 呢?如果没有 reified 关键字, 我们只能通过反射来获取。比如下面的代码

private fun <T : Any> BaseMapper<T>.entityClass(): Class<T> {  
    val searchEntityClass = javaClass.searchEntityClass<T>()  
    if (searchEntityClass != null) {  
        return searchEntityClass  
    }  
    throw IllegalArgumentException("无法获取实体类")  
}
private fun <T> Class<*>.searchEntityClass(): Class<T>? {
    for (type in genericInterfaces) {
        if (type is ParameterizedType) {
            if (type.rawType == BaseMapper::class.java) {
                return type.actualTypeArguments[0] as Class<T>
            }
        } else {
            if (type is Class<*>) {
                return type.searchEntityClass()
            }
        }
    }
    return null

}

这时候如果我们使用 内联函数 + reified 类型参数,就可以避免使用反射来获取泛型类型。比如下面的代码

inline fun <reified T : Any> BaseMapper<T>.query(): KtQueryChainWrapper<T> {
    // 在使用了reified 类型参数后,就可以直接使用 T::class.java 来获取泛型类型
    return KtQueryChainWrapper(baseMapper = this, entityClass = T::class.java)  
}

可以看到,使用了 reified 类型参数后,就可以直接使用 T::class.java 来获取泛型类型,而不需要通过反射来获取。

课程设计报告:总体方案设计说明 一、软件开发环境配置 本系统采用C++作为核心编程语言,结合Qt 5.12.7框架进行图形用户界面开发。数据库管理系统选用MySQL,用于存储用户数据与小精灵信息。集成开发环境为Qt Creator,操作系统平台为Windows 10。 二、窗口界面架构设计 系统界面由多个功能模块构成,各模块职责明确,具体如下: 1. 起始界面模块(Widget) 作为应用程序的入口界面,提供初始导航功能。 2. 身份验证模块(Login) 负责处理用户登录与账户注册流程,实现身份认证机制。 3. 游戏主大厅模块(Lobby) 作为用户登录后的核心交互区域,集成各项功能入口。 4. 资源管理模块(BagWidget) 展示用户持有的全部小精灵资产,提供可视化资源管理界面。 5. 精灵详情模块(SpiritInfo) 呈现选定小精灵的完整属性数据与状态信息。 6. 用户名录模块(UserList) 系统内所有注册用户的基本信息列表展示界面。 7. 个人资料模块(UserInfo) 显示当前用户的详细账户资料与历史数据统计。 8. 服务器精灵选择模块(Choose) 对战准备阶段,从服务器可用精灵池中选取参战单位的专用界面。 9. 玩家精灵选择模块(Choose2) 对战准备阶段,从玩家自有精灵库中筛选参战单位的操作界面。 10. 对战演算模块(FightWidget) 实时模拟精灵对战过程,动态呈现战斗动画与状态变化。 11. 对战结算模块(ResultWidget) 对战结束后,系统生成并展示战斗结果报告与数据统计。 各模块通过统一的事件驱动机制实现数据通信与状态同步,确保系统功能的连贯性与数据一致性。界面布局遵循模块化设计原则,采用响应式视觉方案适配不同显示环境。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
D3.js作为一种基于JavaScript的数据可视化框架,通过数据驱动的方式实现对网页元素的动态控制,广泛应用于网络结构的图形化呈现。在交互式网络拓扑可视化应用中,该框架展现出卓越的适应性与功能性,能够有效处理各类复杂网络数据的视觉表达需求。 网络拓扑可视化工具借助D3.js展示节点间的关联结构。其中,节点对应于网络实体,连线则表征实体间的交互关系。这种视觉呈现模式有助于用户迅速把握网络整体架构。当数据发生变化时,D3.js支持采用动态布局策略重新计算节点分布,从而保持信息呈现的清晰度与逻辑性。 网络状态监测界面是该工具的另一个关键组成部分,能够持续反映各连接通道的运行指标,包括传输速度、响应时间及带宽利用率等参数。通过对这些指标的持续追踪,用户可以及时评估网络性能状况并采取相应优化措施。 实时数据流处理机制是提升可视化动态效果的核心技术。D3.js凭借其高效的数据绑定特性,将连续更新的数据流同步映射至图形界面。这种即时渲染方式不仅提升了数据处理效率,同时改善了用户交互体验,确保用户始终获取最新的网络状态信息。 分层拓扑展示功能通过多级视图呈现网络的层次化特征。用户既可纵览全局网络架构,也能聚焦特定层级进行细致观察。各层级视图支持展开或收起操作,便于用户开展针对性的结构分析。 可视化样式定制系统使用户能够根据实际需求调整拓扑图的视觉表现。从色彩搭配、节点造型到整体布局,所有视觉元素均可进行个性化设置,以实现最优的信息传达效果。 支持拖拽与缩放操作的交互设计显著提升了工具的使用便利性。用户通过简单的视图操控即可快速浏览不同尺度的网络结构,这一功能降低了复杂网络系统的认知门槛,使可视化工具更具实用价值。 综上所述,基于D3.js开发的交互式网络拓扑可视化系统,整合了结构展示、动态布局、状态监控、实时数据处理、分层呈现及个性化配置等多重功能,形成了一套完整的网络管理解决方案。该系统不仅协助用户高效管理网络资源,还能提供持续的状态监测与深度分析能力,在网络运维领域具有重要应用价值。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
代码转载自:https://pan.quark.cn/s/74eb7b5f49ba DIPm 一个使用MATLAB App Designer开发的简单数字图像处理APP 图像处理函数 自动调整 降噪 :二维自适应去噪滤波 基于图像的局部统计特性来估计噪声方差,并根据噪声的特性进行滤波。 这种滤波方法通常在存在噪声的图像中能够有效地减少噪声并保持图像的细节。 伽马校正 :将线性 RGB 值应用伽马校正,使其转换为适合显示的 sRGB 色彩空间。 对图像中的像素值进行非线性变换,使较暗区域的细节更加可见,同时保持较亮区域的细节不被过度压缩。 这样可以增强图像的对比度,使其在显示时更加生动和自然。 自动白平衡 当人们用眼晴观察自然世界时,在不同的光线下,对相同颜色的感觉基本是相同的,大脑已经对不同光线下的物体的彩色还原有了适应性。 这种现象称为颜色恒常性。 不幸的是,CMOS或CCD等感光器件没有这样的适应能力。 为了使得摄像机也具有颜色恒常性能力,需要使用白平衡技术。 所谓白平衡(WiteBalance),简单地说就是去除环境光的影响,还原物体真实的颜色,把不同色温下的白颜色调整正确。 从理论上说白颜色调整正确了,其他色彩就都准确了。 即在红色灯光照射下,白色物体依然呈白色,在蓝色灯光照射下也呈现白色。 灰度世界算法以灰度世界假设为基础,该假设认为:对于一幅有着大量色彩变化的图像,其R,G,B 三个色彩分量的平均值趋于同一灰度值 K。 从物理意义上讲,灰色世界法假设自然界景物对于光线的平均反射的均值在总体上是个定值,这个定值近似地为“灰色”。 颜色平衡算法将这一假设强制应用于待处理图像,可以从图像中消除环境光的影响,获得原始场景图像。 自动对比度增强 MATLAB中有三个函数适用...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值