无法理解如何在 Kotlin 中使用 SAM 接口
Can't understand how to use SAM interface in Kotlin
我不明白为什么下面的代码有效:
山姆接口:
fun interface WebResponseHandler
{
fun onWebResponseFinished(jsonObject:JSONObject)
}
并且 Implemnetaiton 看起来像:
val onWebResponseHandler: VolleyHandler.WebResponseHandler = VolleyHandler.WebResponseHandler()
{
fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", "dsa")
}
fun foo() {
it.getString("name")
}
}
foo 函数如何知道 it 是什么?毕竟,foo 函数不是 VolleyHandler.WebResponseHandler 接口的一部分,它仅当接口仅作为一个 method.Function Foo 在没有任何参数的情况下被调用时才有效,那么为什么 it 的含义在那里?
此外,如果我在尝试实现接口时从接口声明中省略关键字 fun,则会出现另一个问题:
val onWebResponseHandler: VolleyHandler.WebResponseHandler = VolleyHandler.WebResponseHandler()
{
fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", "dsa")
}
fun foo() {
Log.v("something", "something")
}
}
我收到一个编译错误
Interface WebResponseHandler does not have constructors
这两种情况有什么不同?如果我删除 () 我会收到很多不同的错误,例如:
Function declaration must have a name
我希望有人能弄清楚这里有什么问题
不是 Kotlin 很乱,而是你使用了错误的语法来做你想做的事情。
fun interface
让你做的就是写
val onWebResponseHandler = VolleyHandler.WebResponseHandler {
jsonObject: JSONObject -> Log.v("da", "dsa")
}
你可以用普通界面做的是写
val onWebResponseHandler = object : VolleyHandler.WebResponseHandler() {
fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", "dsa")
}
fun foo() {
Log.v("something", "something")
}
}
您的代码执行了 none 的这些操作,并且在编译时不会执行您想要的任何操作。你写的相当于
val onWebResponseHandler = VolleyHandler.WebResponseHandler() {
unusedJsonObject: JSONObject ->
fun aFunctionWhichIsDefinedAndNeverCalled(jsonObject: JSONObject) {
Log.v("da", "dsa")
}
fun anotherFunctionWhichIsDefinedAndNeverCalled() {
unusedJsonObject.getString("name")
}
// doesn't actually do anything at all when executed
// just defines functions which aren't ever invoked
}
...编译是因为,因为它是一个 fun interface
,你 可以 只是将一个 lambda 传递给构造函数,但实际上并没有做任何类似的事情你期待。
这里有一种不同的解释方式,可能会有帮助。
如果要将接口的实现分配给变量或 属性,通常必须使用像这样的匿名 class 语法。注意 object:
和 override
.
的使用
val onWebResponseHandler = object : VolleyHandler.WebResponseHandler {
override fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", jsonObject.toString())
}
}
您还可以在匿名 class 中定义其他 public 函数,但这毫无意义,因为无法访问匿名 class 的唯一成员,因此您在此示例中将无法调用函数 foo()
:
val onWebResponseHandler = object : VolleyHandler.WebResponseHandler {
override fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", jsonObject.toString())
}
fun foo() {
Log.v("something", "something")
}
}
如果您将接口设为 fun interface
,则可以使用 lambda 语法来定义这样的单个函数。这就是 SAM 转换。它将您的 lambda 视为接口的匿名实现。
val onWebResponseHandler = VolleyHandler.WebResponseHandler { jsonObject ->
Log.v("da", jsonObject.toString())
}
另外,如果一个lambda只有一个参数,你可以省略定义参数名,而简单地命名为it
所以这等同于上面的:
val onWebResponseHandler = VolleyHandler.WebResponseHandler {
Log.v("da", it.toString())
}
另外请注意,您可以在代码中的任何位置定义一个函数,包括在另一个函数的中间。例如:
fun bar() {
fun foo() {
Log.i("foo", "foo")
}
foo()
}
相当于
fun bar() {
val foo: () -> Unit = {
Log.i("foo", "foo")
}
foo() // or foo.invoke()
}
因此,在您的原始代码中,您结合了这些概念来创建一个 lambda 函数,其中定义了其他从未使用过的函数。混淆可能是因为它看起来类似于我的代码块,其中我们使用 object:
语法定义匿名 class。最大的区别是您省略了 object:
和 override
,因此您使用的是 lambda 语法。您的代码相当于:
val onWebResponseHandler = VolleyHandler.WebResponseHandler { jsonObject ->
val onWebResponseFinished: (JSONObject) -> Unit = {
Log.v("da", "dsa")
}
val foo: () -> Unit = {
jsonObject.getString("name")
}
}
如果没有 lambda 语法(SAM 转换),它看起来像
val onWebResponseHandler = object : VolleyHandler.WebResponseHandler {
override fun onWebResponseFinished(jsonObject: JSONObject) {
val onWebResponseFinished: (JSONObject) -> Unit = {
Log.v("da", "dsa")
}
val foo: () -> Unit = {
jsonObject.getString("name")
}
}
}
我不明白为什么下面的代码有效: 山姆接口:
fun interface WebResponseHandler
{
fun onWebResponseFinished(jsonObject:JSONObject)
}
并且 Implemnetaiton 看起来像:
val onWebResponseHandler: VolleyHandler.WebResponseHandler = VolleyHandler.WebResponseHandler()
{
fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", "dsa")
}
fun foo() {
it.getString("name")
}
}
foo 函数如何知道 it 是什么?毕竟,foo 函数不是 VolleyHandler.WebResponseHandler 接口的一部分,它仅当接口仅作为一个 method.Function Foo 在没有任何参数的情况下被调用时才有效,那么为什么 it 的含义在那里?
此外,如果我在尝试实现接口时从接口声明中省略关键字 fun,则会出现另一个问题:
val onWebResponseHandler: VolleyHandler.WebResponseHandler = VolleyHandler.WebResponseHandler()
{
fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", "dsa")
}
fun foo() {
Log.v("something", "something")
}
}
我收到一个编译错误
Interface WebResponseHandler does not have constructors
这两种情况有什么不同?如果我删除 () 我会收到很多不同的错误,例如:
Function declaration must have a name
我希望有人能弄清楚这里有什么问题
不是 Kotlin 很乱,而是你使用了错误的语法来做你想做的事情。
fun interface
让你做的就是写
val onWebResponseHandler = VolleyHandler.WebResponseHandler {
jsonObject: JSONObject -> Log.v("da", "dsa")
}
你可以用普通界面做的是写
val onWebResponseHandler = object : VolleyHandler.WebResponseHandler() {
fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", "dsa")
}
fun foo() {
Log.v("something", "something")
}
}
您的代码执行了 none 的这些操作,并且在编译时不会执行您想要的任何操作。你写的相当于
val onWebResponseHandler = VolleyHandler.WebResponseHandler() {
unusedJsonObject: JSONObject ->
fun aFunctionWhichIsDefinedAndNeverCalled(jsonObject: JSONObject) {
Log.v("da", "dsa")
}
fun anotherFunctionWhichIsDefinedAndNeverCalled() {
unusedJsonObject.getString("name")
}
// doesn't actually do anything at all when executed
// just defines functions which aren't ever invoked
}
...编译是因为,因为它是一个 fun interface
,你 可以 只是将一个 lambda 传递给构造函数,但实际上并没有做任何类似的事情你期待。
这里有一种不同的解释方式,可能会有帮助。
如果要将接口的实现分配给变量或 属性,通常必须使用像这样的匿名 class 语法。注意 object:
和 override
.
val onWebResponseHandler = object : VolleyHandler.WebResponseHandler {
override fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", jsonObject.toString())
}
}
您还可以在匿名 class 中定义其他 public 函数,但这毫无意义,因为无法访问匿名 class 的唯一成员,因此您在此示例中将无法调用函数 foo()
:
val onWebResponseHandler = object : VolleyHandler.WebResponseHandler {
override fun onWebResponseFinished(jsonObject: JSONObject) {
Log.v("da", jsonObject.toString())
}
fun foo() {
Log.v("something", "something")
}
}
如果您将接口设为 fun interface
,则可以使用 lambda 语法来定义这样的单个函数。这就是 SAM 转换。它将您的 lambda 视为接口的匿名实现。
val onWebResponseHandler = VolleyHandler.WebResponseHandler { jsonObject ->
Log.v("da", jsonObject.toString())
}
另外,如果一个lambda只有一个参数,你可以省略定义参数名,而简单地命名为it
所以这等同于上面的:
val onWebResponseHandler = VolleyHandler.WebResponseHandler {
Log.v("da", it.toString())
}
另外请注意,您可以在代码中的任何位置定义一个函数,包括在另一个函数的中间。例如:
fun bar() {
fun foo() {
Log.i("foo", "foo")
}
foo()
}
相当于
fun bar() {
val foo: () -> Unit = {
Log.i("foo", "foo")
}
foo() // or foo.invoke()
}
因此,在您的原始代码中,您结合了这些概念来创建一个 lambda 函数,其中定义了其他从未使用过的函数。混淆可能是因为它看起来类似于我的代码块,其中我们使用 object:
语法定义匿名 class。最大的区别是您省略了 object:
和 override
,因此您使用的是 lambda 语法。您的代码相当于:
val onWebResponseHandler = VolleyHandler.WebResponseHandler { jsonObject ->
val onWebResponseFinished: (JSONObject) -> Unit = {
Log.v("da", "dsa")
}
val foo: () -> Unit = {
jsonObject.getString("name")
}
}
如果没有 lambda 语法(SAM 转换),它看起来像
val onWebResponseHandler = object : VolleyHandler.WebResponseHandler {
override fun onWebResponseFinished(jsonObject: JSONObject) {
val onWebResponseFinished: (JSONObject) -> Unit = {
Log.v("da", "dsa")
}
val foo: () -> Unit = {
jsonObject.getString("name")
}
}
}