简体   繁体   English

Kotlin function 参数:如何定义一个 function 可以有一个尾随的参数 Z945F3ZFC449518A7629 的接口为?

[英]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
}

Why doesn't it work exactly?为什么它不能完全工作?

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)方法。

Update (official documentation)更新(官方文档)

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 开始提供,该版本现在是一个候选版本。

Update with a solution更新解决方案

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM