Kotlin 接口函数作为表达式体
Kotlin interface function as expression body
在 Kotlin 中编写函数时,基本上完全在 Thread
创建内部实现,它是 start()
,Android Studio 提供了“转换为表达式主体”的选项
选择这样做时,kotlin 将函数转换为表达式主体:
有没有办法为接口要求这个(比如这个函数覆盖的那个)?
我希望界面总是需要 validate
函数来启动一个新的 Thread
并且只有 (!!) 能够执行那个 Thread
里面的东西,而不是在方法体本身,因为它只会用于寻址服务器。
我知道我可以通过使用 abstract class
而不是 interface
来强制这种行为:
abstract class ServerValidator<T> {
fun validate(value: T?, function: ((ValidationResult) -> Unit)) = Thread {
doValidation(value, function)
}.start()
protected abstract fun doValidation(value: T?, function: ((ValidationResult) -> Unit))
}
这样继承的 class 将能够覆盖 doValidation
函数,而另一个 class 将只能调用 validate
从而始终使用新的线程。
但是,我特别想知道是否可以使用接口来做这样的事情。
类似于:
interface ServerValidator<T> {
fun validate(value: T?, function: ((ValidationResult) -> Unit)) = Thread::start
}
// or
interface ServerValidator<T> {
fun validate(value: T?, function: ((ValidationResult) -> Unit)) : Thread::start
}
表达式体与函数签名无关。它纯粹是一种语法选择。在您的示例的两种情况下,函数都返回 Unit
因为在表达式主体情况下,它返回 Thread.start()
returns,即 Unit
.
我认为您实际上要问的是,您是否不仅可以定义一个函数 returns,还可以定义它如何获得该结果的中间步骤,即强制它在后台执行某些操作线。答案是否定的。语言中没有任何东西可以定义这样的结构。
您已经描述了正确的方法,即获取一个函数参数,然后接收方 class 可以在后台线程中自行调用它。
另一种方法可能是将函数定义为 suspend
函数,这意味着它不应在不使用适当的协程调度程序来阻塞代码的情况下执行阻塞代码。然后,如果实现接口函数的人未能使用后台 Dispatcher,他们就违反了 suspend
函数应该如何工作的约定。但是编译器仍然不会强制他们正确地做。
表达式主体只是编写功能块的另一种方式,作为单个表达式而不是使用带有 return 的大括号。它可以更简洁、更具表现力(特别是因为您可以省略 return 类型)。
可以说你应该只对 return Unit 以外的表达式使用表达式主体(即它们 return 一个值而不是有副作用) ,但没有任何强制措施。
你关于接口的问题完全是另一回事,据我所知,没有办法强制函数实现包含特定行为。我认为让您的接口函数定义验证过程(或 return 您可以 运行 执行该验证的函数)并将其分派给实际上 运行 它(这就是你可以控制它是否使用工作线程、线程池、协程等的地方)
在 Kotlin 中编写函数时,基本上完全在 Thread
创建内部实现,它是 start()
,Android Studio 提供了“转换为表达式主体”的选项
选择这样做时,kotlin 将函数转换为表达式主体:
有没有办法为接口要求这个(比如这个函数覆盖的那个)?
我希望界面总是需要 validate
函数来启动一个新的 Thread
并且只有 (!!) 能够执行那个 Thread
里面的东西,而不是在方法体本身,因为它只会用于寻址服务器。
我知道我可以通过使用 abstract class
而不是 interface
来强制这种行为:
abstract class ServerValidator<T> {
fun validate(value: T?, function: ((ValidationResult) -> Unit)) = Thread {
doValidation(value, function)
}.start()
protected abstract fun doValidation(value: T?, function: ((ValidationResult) -> Unit))
}
这样继承的 class 将能够覆盖 doValidation
函数,而另一个 class 将只能调用 validate
从而始终使用新的线程。
但是,我特别想知道是否可以使用接口来做这样的事情。
类似于:
interface ServerValidator<T> {
fun validate(value: T?, function: ((ValidationResult) -> Unit)) = Thread::start
}
// or
interface ServerValidator<T> {
fun validate(value: T?, function: ((ValidationResult) -> Unit)) : Thread::start
}
表达式体与函数签名无关。它纯粹是一种语法选择。在您的示例的两种情况下,函数都返回 Unit
因为在表达式主体情况下,它返回 Thread.start()
returns,即 Unit
.
我认为您实际上要问的是,您是否不仅可以定义一个函数 returns,还可以定义它如何获得该结果的中间步骤,即强制它在后台执行某些操作线。答案是否定的。语言中没有任何东西可以定义这样的结构。
您已经描述了正确的方法,即获取一个函数参数,然后接收方 class 可以在后台线程中自行调用它。
另一种方法可能是将函数定义为 suspend
函数,这意味着它不应在不使用适当的协程调度程序来阻塞代码的情况下执行阻塞代码。然后,如果实现接口函数的人未能使用后台 Dispatcher,他们就违反了 suspend
函数应该如何工作的约定。但是编译器仍然不会强制他们正确地做。
表达式主体只是编写功能块的另一种方式,作为单个表达式而不是使用带有 return 的大括号。它可以更简洁、更具表现力(特别是因为您可以省略 return 类型)。
可以说你应该只对 return Unit 以外的表达式使用表达式主体(即它们 return 一个值而不是有副作用) ,但没有任何强制措施。
你关于接口的问题完全是另一回事,据我所知,没有办法强制函数实现包含特定行为。我认为让您的接口函数定义验证过程(或 return 您可以 运行 执行该验证的函数)并将其分派给实际上 运行 它(这就是你可以控制它是否使用工作线程、线程池、协程等的地方)