[英]Kotlin function parameter: how to define a function which can have a trailing lambda or interface as a parameter?
I found two similar codes:我发现了两个类似的代码:
binding.playButton.setOnClickListener (
Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment)
)
binding.playButton.setOnClickListener {
Navigation.findNavController(it).navigate(R.id.action_titleFragment_to_gameFragment)
}
Java code from android view class: Java 代码来自 android 查看 class:
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
The question is: how can I create such function where I can use trailing lambda or interface as parameter?问题是:如何创建这样的 function 可以使用尾随 lambda 或接口作为参数? I get type mismatch.我得到类型不匹配。
interface One {
fun a(): Int
}
class OneImp : One {
override fun a(): Int {
return 4
}
}
fun test(one: One) {
val a = one
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val a = OneImp()
test (a) //works fine
test {
a //error
}
}
Error:错误:
Type mismatch.
Required:
TitleFragment.One
Found:
() → TitleFragment.OneImp
UPDATE:更新:
After the answer of @Jenea Vranceanu, I have found my error in testing SAM (I used interface from kotlin file, while all the code should be in java).在@Jenea Vranceanu 的回答之后,我在测试SAM 时发现了我的错误(我使用了kotlin 文件中的接口,而所有代码都应该在java 中)。 Solution will be: (before kotlinv v1.4 releases) create a java file:解决方案是:(在 kotlinv v1.4 发布之前)创建一个 java 文件:
public class Mine {
public interface One {
int a();
}
public class OneImpl implements One {
@Override
public int a() {
return 4;
}
}
public void test(One one) {}
}
Then I can use both function argument and lambda.然后我可以同时使用 function 参数和 lambda。 In kotlin file now:现在在 kotlin 文件中:
Mine().test {4}
val b = Mine().OneImpl()
Mine().test (b)
PS. PS。 If he adds it to his answer I will delete if from here.如果他将其添加到他的答案中,我将从此处删除。
You have misunderstood a little bit how binding.playButton.setOnClickListener
worked in each case.您误解了binding.playButton.setOnClickListener
在每种情况下的工作方式。
In the first one, Navigation
component creates View.OnClickListener
that is passed into setOnClickListener
(notice parentheses or round brackets):在第一个中, Navigation
组件创建View.OnClickListener
并传递给setOnClickListener
(注意括号或圆括号):
binding.playButton.setOnClickListener (
Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment)
)
In Java it would look almost the same:在 Java 中看起来几乎相同:
binding.getPlayButton().setOnClickListener (
Navigation.createNavigateOnClickListener(R.id.action_titleFragment_to_gameFragment)
)
The second example works a little bit differently.第二个示例的工作方式略有不同。 First, you create View.OnClickListener
by using braces and you define the body of this View.OnClickListener
method onClick(View view)
:首先,使用大括号创建View.OnClickListener
并定义此View.OnClickListener
方法onClick(View view)
的主体:
binding.playButton.setOnClickListener { /* empty body of onClick(View view) */ }
You have reference to the clicked view inside of braces:您参考了大括号内的单击视图:
binding.playButton.setOnClickListener {
it.context // `it` is the clicked view
}
// It is the same as
binding.playButton.setOnClickListener { view ->
view.context
}
This type of defining anonymous classes is possible only with SAM classes defined in Java and View.OnClickListener
is a SAM class defined in Java.这种定义匿名类的类型仅适用于 Java 中定义的 SAM 类,并且View.OnClickListener
是 Java 中定义的 SAM class。 Kotlin SAM classes/interfaces do not support this feature yet. Kotlin SAM 类/接口尚不支持此功能。
By writing:通过写作:
val a = OneImp()
test {
a //error
}
You assume that test
function declaration looks like this:您假设test
function 声明如下所示:
fun test(one: () -> One) {
val a = one()
}
Note that in the second example you have at the top of your question Navigation.findNavController(it).navigate
does not create View.OnClickListener
object.请注意,在第二个示例中,您的问题Navigation.findNavController(it).navigate
不会创建View.OnClickListener
object。 The braces create this object and as this interface has only one abstract method there is no use to write this method signature so all the content declared inside of braces goes directly into void onClick(View view)
method.大括号创建了这个 object并且由于该接口只有一个抽象方法,因此没有必要编写此方法签名,因此大括号内声明的所有内容都直接进入void onClick(View view)
方法。
SAM conversions in Kotlin . Kotlin 中的 SAM 转换。 This is the official documentation and at the bottom of it is written:这是官方文档,底部写着:
... note that this feature works only for Java interop; ...请注意,此功能仅适用于 Java 互操作; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.由于 Kotlin 具有正确的 function 类型,因此不需要将功能自动转换为 Kotlin 接口的实现,因此不受支持。
So it will never be supported for Kotlin interfaces as there is no need for it.
因此,Kotlin 接口永远不会支持它,因为不需要它。
As it appears I was wrong about "SAM will never be supported".看来我对“永远不会支持SAM”是错误的。 It will be but it is not yet available.它将是,但它尚不可用。 SAM conversions for Kotlin classes will be available starting from Kotlin 1.4 which is now a release candidate. Kotlin 类的 SAM 转换将从 Kotlin 1.4 开始提供,该版本现在是一个候选版本。
The alternative solution was not added initially.最初没有添加替代解决方案。 Questioner politely requested to add the next code to make the answer complete.发问者礼貌地要求添加下一个代码以使答案完整。 Thanks!谢谢!
public class Mine {
public interface One {
int a();
}
public class OneImpl implements One {
@Override public int a() { return 4; }
}
public void test(One one) {}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.