【问题标题】:How to enforce generic type with Kotlin interop如何使用 Kotlin 互操作强制泛型类型
【发布时间】:2015-02-12 14:56:53
【问题描述】:

我在 Kotlin 中有一个方法,它返回一个通用列表的 Rx Observable:

public fun getObservable(): Observable<List<FooBar>> {
    return Observable.just(theList)
}

因为 Kotlin 列表 trait 被定义为 List&lt;out T&gt;,Java 会将返回类型视为 Observable&lt;List&lt;? extends FooBar&gt;&gt;

有没有办法告诉 Kotlin 编译器 Java 应该将其视为 Observable&lt;List&lt;FooBar&gt;&gt;

http://kotlinlang.org/docs/reference/generics.html

更新以正确显示问题。

【问题讨论】:

  • 解决此问题的一种方法是使用MutableList,但是如果getList() 请求不可变的返回类型,这将无济于事。
  • 你不能简单地用 Java 进行转换吗?
  • 是的,这是可能的,但是我不希望在这种情况的每个实例中都使用演员表。此外,问题更多的是对 Kotlin 对这种情况的语言可供性的好奇。
  • 我刚刚测试过,我可以在Java中使用kotlin方法fun getList(): List&lt;String&gt;List&lt;String&gt; list = TestPackage.getList();所以我看不到你描述的问题。
  • 你是对的@SalomonBRYS。我更新了问题。

标签: java generics interop kotlin


【解决方案1】:

您可以使用 JvmWildcardJvmSuppressWildcards 注释控制 Java 如何看待 Kotlin 泛型。它是在 Kotlin 1.0 Beta 4 中添加的(请参阅 announcement)。

此更改意味着您的代码已经更改为可以,并且不再生成通配符。因为新的默认设置是在很多情况下不使用它们,您可以使用注释将它们带回来或在不需要时将它们隐藏。

此更改的公告指出:

Java 通配符

Kotlin 如何翻译变体类型存在问题,例如List 应该是 Java 中的 List 还是简单的 List。除了细微的细节,我们做了以下事情:

  • 默认情况下,我们不会在返回类型和它们没有意义的地方生成通配符
  • 当需要通配符时,可以使用类型注释强制其存在:List 在 Java 中始终是 List
  • 当我们需要去除通配符时,我们可以使用@JvmSuppressWildcards(这可以用于类型或包含它的任何声明)

例子:

fun foo(l: List<String>) // in Java: List<String> (String is final)
fun foo(l: List<@JvmWildcard String>) // in Java: List<? extends String>

interface Open {}
fun bar(p: List<Open>) // in Java: List<? extends Open> (Open is not final)
@JvmSuppressWildcards
fun bar(p: List<Open>) // in Java: List<Open>

因此,如果您仍然遇到问题,请将此应用于您的问题:

@JvmSuppressWildcards
public fun getObservable(): Observable<List<FooBar>> {
    return Observable.just(theList)
}

【讨论】:

    【解决方案2】:

    编辑:这种行为在 Kotlin Beta 4 中有所改变。请参阅 Jayson Minard 的 answer

    我可以看到两个选项:

    • 首先是返回一个Observable&lt;MutableList&lt;FooBar&gt;&gt;。因为 List 在 kotlin 中是不可变的,所以它被声明为 List&lt;out T&gt; 因为类型 T 的对象只能取出它。
      MutableList 另一方面是 Java 的 true List 等价物:因为它是可变的,所以它被声明为 MutableList&lt;T&gt;
      所以你的功能是:

      public fun getObservable(): Observable<MutableList<FooBar>>
              = Observable.just(theList)
      

      此解决方案的问题在于,如果您在 kotlin 中使用它,如果您只想拥有一个不可变列表的 Observable,则您授予对列表的“太多”访问权限。

    • 第二种选择是在java中编写一个“代理”方法,使演员一劳永逸:

      @SuppressWarnings("unchecked")
      public static Observable<List<String>> _getObservable() { return (Observable) TestPackage.getObservable(); }
      

      这很难看,但它有效,并且不会破坏 kotlin

      但是,我假设您使用的是 RxJava 的 Observable,那么为什么不利用这个机会在 Java 中强制执行 kotlin 的不可变列表语义呢?

      public static Observable<List<String>> _getObservable() {
          return TestPackage.getObservable().map(new Func1<List<? extends String>, List<String>>() {
              @Override
              public List<String> call(List<? extends String> list) {
                  return Collections.unmodifiableList(list);
              }
          });
      }
      

    【讨论】:

    • 我喜欢第一个选项,因为 java.util.List 是可变的,但是我喜欢你的第三个选项,因为我看到我们将更多代码转移到 Kotlin。谢谢!
    • 此行为已更改,请参阅new answer below
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多