Kotlin可空类型的扩展函数仅限

huangapple go评论58阅读模式
英文:

Kotlin extension function for nullable types ONLY

问题

fun String.ext(): Unit = TODO()
fun String?.nullExt(): Unit = TODO()
英文:

Examine this code:

fun f(nullString: String?, nonNullString: String) {
	nullString.ext() // Error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
	nullString.nullExt() // OK, nullabilities match
	nonNullString.ext() // OK, nullabilities match
	nonNullString.nullExt() // Expected error: nullExt is only applicable to String?
}

I would like to write two function signatures that makes the first and last function call not compile.

This makes the first line a compile error, but the last line still compiles:

fun String.ext(): Unit = TODO()
fun String?.nullExt(): Unit = TODO()

As far as I understand this works because "String extends String?", so defining an extension on String? is similar to defining one on CharSequence. Is there a way to prevent this from compiling?

答案1

得分: 2

以下是要翻译的内容:

A possible solution is to forbid the compiler to pick the "super" implementation, by declaring a more specific one:

fun String.ext(): Unit = TODO()
fun String?.nullExt(): Unit = TODO()

@Deprecated(
	message = "nullExt is only applicable to nullable receivers.",
	level = DeprecationLevel.ERROR,
	replaceWith = ReplaceWith("")
)
fun String.nullExt(): Unit =
	error("This should never be called.")

Note: String! will resolve to String overload.


A real use case in case anyone is wondering:

fun <T : Any?> T?.orError(message: String): T & Any =
	this ?: error(message)

@Deprecated(
	message = "orError is only applicable to nullable receivers.",
	level = DeprecationLevel.ERROR,
	replaceWith = ReplaceWith("")
)
fun <T : Any> T.orError(message: String): Nothing =
	error("This should never be called.")

we wouldn't want somethingNonNull.orError() because in that case orError() will never execute and therefore it is dead code.

英文:

A possible solution is to forbid the compiler to pick the "super" implementation, by declaring a more specific one:

fun String.ext(): Unit = TODO()
fun String?.nullExt(): Unit = TODO()

@Deprecated(
	message = &quot;nullExt is only applicable to nullable receivers.&quot;,
	level = DeprecationLevel.ERROR,
	replaceWith = ReplaceWith(&quot;&quot;)
)
fun String.nullExt(): Unit =
	error(&quot;This should never be called.&quot;)

Note: String! will resolve to String overload.


A real use case in case anyone is wondering:

fun &lt;T : Any?&gt; T?.orError(message: String): T &amp; Any =
	this ?: error(message)

@Deprecated(
	message = &quot;orError is only applicable to nullable receivers.&quot;,
	level = DeprecationLevel.ERROR,
	replaceWith = ReplaceWith(&quot;&quot;)
)
fun &lt;T : Any&gt; T.orError(message: String): Nothing =
	error(&quot;This should never be called.&quot;)

we wouldn't want somethingNonNull.orError() because in that case orError() will never execute and therefore it is dead code.

huangapple
  • 本文由 发表于 2023年5月24日 21:32:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76324111.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定