kotlin - 要求和断言有什么区别?
问题描述
Kotlin 1.3带来了一个新特性,即契约,以及随之而来的函数require()
,但它看起来与assert()
. 这是他们的 KDoc 所说的:
require(value: Boolean)
IllegalArgumentException
:如果value
为假,则抛出一个。
assert(value: Boolean)
AssertionError
:如果value
为 false 并且使用 -ea JVM 选项在 JVM 上启用了运行时断言,则抛出一个。
那么我应该什么时候使用require()
,什么时候应该使用assert()
呢?
解决方案
require
并assert
以不同的方式工作。为此,您需要深入研究代码。
assert(condition)
在内部调用不同的方法,这是您看到实际代码的地方:
@kotlin.internal.InlineOnly
public inline fun assert(value: Boolean, lazyMessage: () -> Any) {
if (_Assertions.ENABLED) {
if (!value) {
val message = lazyMessage()
throw AssertionError(message)
}
}
}
AFAIK,这与-ea
国旗有关;如果-ea
不存在(或禁用),assert
则不会引发异常。
结果,这将无法编译:
fun something(string: String?){
assert (string != null)
nonNull(string) // Type mismatch
}
fun nonNull(str: String){}
这就是 require 的用武之地。require(condition)
还在后台调用了不同的方法。如果替换assert
为require
,您将看到智能转换将成功地将其转换为非 null,因为require
如果条件失败,保证会抛出异常。
@kotlin.internal.InlineOnly
public inline fun require(value: Boolean, lazyMessage: () -> Any): Unit {
contract {
returns() implies value
}
if (!value) {
val message = lazyMessage()
throw IllegalArgumentException(message.toString())
}
}
仅布尔函数也执行合约,然后在合约失败时调用该方法。
合同是新的,我不完全确定它们是如何工作的,但这就是我的理解:
关键字implies
是; infix fun
它的作用是告诉编译器如果从方法返回条件为真。这有助于自动投射,就像我之前提到的示例一样。它实际上并没有导致方法返回(或者至少这是我当前的测试所指向的),但它是针对编译器的。
它也是可读的:returning implies condition is true
那是联系部分:这里的异常总是被抛出,正如你从条件中看到的那样。require
使用if(!value)
, where asassert
检查if(_Assertions.ENABLED && !value)
.
这不是唯一的用途require
。它也可以用于验证参数。即如果你有这个:
operator fun get(index: Int) : T {
if (index < 0 || index >= size)
throw IllegalArgumentException("Index out of range")
// return here
}
您可以将其替换为:
operator fun get(index: Int) : T {
require (index >= 0 && index < size) { "Index out of range" }
// return here
}
这有很多不同的用途,但这些只是一些例子。
这意味着什么:
assert
就像在Java中一样;只有在启用断言时才会触发它。使用它并不能保证满足条件。require
始终有效,无论 VM 标志如何
这意味着require
可以用来帮助编译器进行智能转换,并且使用它比assert
确保参数有效要好。而且由于它也可以不受 VM 标志的影响,因此它可以在调试案例之外使用,如 forpas 所述。如果你正在制作一个用 Kotlin 编写的库,你可以用手动抛出替换参数检查require
,它仍然可以工作。显然,这是假设 Kotlin 1.3.0,但这不是重点。
它可以在内部使用以确保智能转换按预期工作,但如果不满足条件则抛出异常。
不过要回答你的问题:
- 当您想要进行参数检查时使用
require
,即使它在生产中。 assert
如果您正在进行本地调试并-ea
启用该标志,请使用此选项。
推荐阅读
- android - Activity 销毁时,AnyChartView 出现内存泄漏
- python - 将重复的列从 CSV 转换为嵌套的 BigQuery 表?
- python - 如何让服务器的创建者选择新用户加入服务器的机器人消息将被发送到哪里?
- javascript - 如何防止下拉选项从 CSS 中的其他下拉菜单中隐藏?
- ios - 在 GraphQL Apollo Client iOS 中模拟 JSON 数据解析
- sql - 生成所有组合
- class - Dart Flutter:为类属性设置默认值时的语法混淆
- java - 递归添加元素到 ArrayList 时并发修改异常
- linux - 在适用于 Linux 的 Azure 应用服务中运行 .NET Core API 的性能问题
- ruby-on-rails - 如何通过一个查询访问两个多态关联?