Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.6k views
in Technique[技术] by (71.8m points)

kotlin - Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?

fun checkLengthA(str : String?): Int = if (str.isNullOrBlank()) 0 else str.length

"Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?

all null objects (or empty) are caught by isNullOrBlank(), so the str object in str.length can never be null (or empty). This can be achieved by replacing extension function with an explicit check.

fun checkLengthB(str : String?): Int = if (str == null) 0 else str.length

or less verbose expression:

fun checkLengthC(str : String?): Int = str?.length ?: 0

Both checkLengthB and checkLengthC will run without problems.

Let's remove the nullable type from checkLengthA to avoid the compile error, highlighted above:

fun checkLengthA(str : String): Int = if (str.isNullOrBlank()) 0 else str.length

Now, we are only allowed to pars use non-null parameter of type String, so if we expect some null types then we have to put the "?" back.

Looks like the complier does not understand that str of type String will never evaluate to null when running str.length and an extension function, but it will compile without problems if we use (str == null) in the if-else statement.

Can anyone explain why it is happening?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is no way for the compiler to prove that after isNullOrBlank evaluates to false, that the argument must not be null. isNullOrBlank is just a normal method, the same argument could apply to any number of functions that check whether an argument is null. What if someone changed the implementation of isNullOrBlank to always return false?

In the case of arg == null, the compiler knows that this must mean the argument is not null, as, well, that's exactly what == null means, syntactically and literally.

Note that == null does not always result in a safe cast, for example, when the variable being checked is a property.

In this case:

str?.length ?: 0

there are no smart casts involved.

str?.length is an Int?, and with the Elvis operator ?: you will end up with an Int.


Interestingly, the implementation of isNullOrBlank contains this contract:

contract {
    returns(false) implies (this@isNullOrBlank != null)
}

so maybe this will be supported at some point.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...