今天,在编程时,我在Kotlin中发现了一些奇怪的行为。我可以轻而易举地解决它,但是我想知道是出于某种原因还是Kotlin中的错误。
我具有以下委托接口,该接口将对话框的显示委托给Activity。
interface ViewModelDelegate {
fun showWarningDialog(textResource: Int)
}
我想在“活动”中按以下方式实现它。因为我知道我只能在上下文中执行此操作,并且Activity.getContext()
可能返回null
,所以我将代码包装在context?.let
override fun showWarningDialog(textResource: Int) = context?.let {
//show dialog
}
但是这给了我一个编译错误:
'showWarningDialog'的返回类型不是重写成员'public abstract fun showWarningDialog(textResource:Int):com.some.class.path中定义的单元”的返回类型的子类型。
这真的使我感到困惑,因为我不想退货。因此,由于let
返回内部返回的任何函数,所以我想知道是否可以通过编写一个不返回任何内容的let版本来修复它。
fun <T, R> T.myLet(block: (T) -> R) {
let(block)
}
但是,这并没有消除编译器错误。然后,我发现该错误上的鼠标悬停文本提供了更多信息(如果编译器这样做的话会很好)。它说:
返回类型为'Unit?',它不是重写的子类型
现在,这可以告诉我更多有关该问题的信息。因为可能不会发生函数context?let
的调用,所以它可能返回null
。现在有多种方法可以解决此问题。我可以在函数调用的末尾添加?: Unit
,也可以定义showWarningDialog
返回Unit?
,这将使我在大多数情况下可以很好地调用它。但是,这些解决方案都不是可取的。我可能只会做一个普通方法并在其中调用let
而不是委托它。花了我另一个缩进级别和一条额外的垂直线:
override fun showWarningDialog(textResource: Int) {
context?.let {
//show dialog
}
}
我的问题是,这种行为是故意的吗?为什么或何时有用,以致不能将返回Unit的函数委派给可选函数调用。这种行为让我很困惑。
答案 0 :(得分:1)
单表达式功能
fun foo() = <expression>
通过语言设计等同于
fun foo(): <ReturnType> {
return <expression>
}
并且由于Unit?
不是Unit
的子类型,因此您不能从返回Unit
的函数中将其返回。从这个意义上说,Unit
只是类型系统中的另一种类型,并不是什么神奇的东西。因此,它就像可以与任何其他类型一起使用一样。
为什么或何时有用,以致不能将返回Unit的函数委派给可选函数调用。
因此,基本上的问题是,为什么语言设计人员没有创建一个特殊处理来接受来自将Unit?
声明为返回类型的函数中的Unit
。我可以考虑以下几个原因:
因此,总结一下,我想说,使此案例行之有效,并没有增加太多价值,但可能会带来一些问题。这可能就是为什么他们没有将其添加到语言中的原因。
答案 1 :(得分:0)
让我们讨论当您有返回类型(例如String
interface someInterface{
fun somFun():String
}
class someClass : someInterface {
var someString:String? = null
override fun somFun()=someString?.let {
//not working
it
}
override fun somFun()=someString?.let {
//working
it
}?:""
}
所以我们看到,当父母的返回类型为String
时,您不能返回Strin?
,这是绝对的nullSafety,
没有返回类型时有什么不同?让我们稍微改变一下代码
interface someInterface{
fun somFun():String
fun unitFun()
}
class someClass : someInterface {
var someString:String? = null
override fun unitFun() {
//if it is possible to return null in here
}
override fun somFun()=someString?.let {
val someresult = unitFun().toString() //you will get crash
it
}?:""
}
现在我们有了另一个没有返回类型(unitFun
Unit
)的函数
因此,如果您可以在子类中返回Unit?
,则在使用方法的结果时将导致崩溃,因为它的定义为Unit
,并且您不需要进行任何null
检查。 / p>
通常,这意味着Unit
也是类型,您需要将其保留为空。