- Learn Kotlin Programming(Second Edition)
- Stephen Samuel Stefan Bocutiu
- 562字
- 2021-06-24 14:13:31
Contracts on a function return value
With a such a contract in place, the Kotlin compiler knows that if the target function returns, then the condition defined is satisfied. This is what the previous example demonstrated. In the preceding scenario, the compiler knows now that if the function returns then the command parameter cannot be null.
In the ContractBuilder interface, defining the syntax to use for contracts, you will find two other variations of returns, as follows:
@ContractsDsl public fun returns(value: Any?): Returns
@ContractsDsl public fun returnsNotNull(): ReturnsNotNull
Using the first function, you can place a condition on the return value for the target function. While the returns takes a parameter of the Any? type, you can only use true, false, or null. In other words, if the function returns true, false, or null, then the effect is considered. The second function listed sets the condition on the target function returning a non-nullable value.
Let's revisit the previous example, this time setting a condition on the return value as follows:
data class Command(val timestamp: Long)
@ExperimentalContracts
fun process(any: Any?) {
if (isCommand(any)) {
println(any.timestamp)
}
}
@ExperimentalContracts
fun isCommand(any: Any?): Boolean {
contract {
returns(true) implies (any is Command)
}
return any is Command
}
While you will never write the code like that, it serves the purpose of demonstrating how you could help the compiler to do a smart cast in the process function. This time, the function takes an Any? parameter, and if the isCommand function returns true then the parameter is of a Command type. Because of this effect, the compiler knows the any parameter is a command, and, therefore, allows you to call any.timestamp.
A contract block is not restricted to one contract. The following code shows how you can set multiple effects on the same code contract:
@ExperimentalContracts
fun compute(any: Any?): Unit {
if (stringOrNumber(any)) {
println("String length:${any.length}")
} else {
for(i in 0..any){
println(i)
}
}
}
@ExperimentalContracts
fun stringOrNumber(value: Any?): Boolean {
contract {
returns(true) implies (value is String)
returns(false) implies (value is Int)
returns() implies (value != null)
}
return when (value) {
is String -> true
is Int -> false
else -> throw IllegalArgumentException()
}
}
Here, a compute method takes an Any? parameter. The stringOrNumber function returns true if the parameter is String or false if the parameter is Int; otherwise, it will throw an exception. This contract allows the body of compute to treat any as String if the method returns true, or as Int if it returns false.
Before moving on to the next contract type, let's close this section with a contract handling more than one argument at once. Consider a stringIntAndBool function taking three Any? arguments and setting a contract for each parameter. When the function returns true, the effect is that the first parameter is String, the second one is Int, and the third one is a Boolean. The following is the code for it:
@ExperimentalContracts
fun stringIntAndBool(val1: Any?, val2: Any?, val3: Any?): Boolean {
contract {
returns(true) implies (
val1 != null && val1 is String &&
val2 != null && val2 is Int &&
val3 != null && val3 is Boolean
)
}
return (val1 is String && val2 is Int && val3 is Boolean)
}
- 零基礎學Visual C++第3版
- 小程序實戰視頻課:微信小程序開發全案精講
- Learn to Create WordPress Themes by Building 5 Projects
- CentOS 7 Server Deployment Cookbook
- Python從入門到精通(精粹版)
- Bulma必知必會
- PHP+MySQL網站開發項目式教程
- Kotlin編程實戰:創建優雅、富于表現力和高性能的JVM與Android應用程序
- 微信小程序全棧開發技術與實戰(微課版)
- Advanced Express Web Application Development
- Android群英傳
- PowerDesigner 16 從入門到精通
- Oracle 12c從入門到精通(視頻教學超值版)
- Julia High Performance(Second Edition)
- Spark技術內幕:深入解析Spark內核架構設計與實現原理