Как передать ограниченный аргумент типа подстановки в Котлин?
Используемый класс (в Java, сторонний API, не изменяемый):
public class BookmarkablePageLink<T> extends Link<T> {
public <C extends Page> BookmarkablePageLink(final String id, final Class<C> pageClass)
И теперь я хочу назвать это от Котлина:
item.queue(BookmarkablePageLink("link", bookmark.page))
bookmark.page
находится в Java, и это: public Class<? extends WebPage> getPage()
public Class<? extends WebPage> getPage()
Ни одна из этих работ:
item.queue(BookmarkablePageLink("link", bookmark.page))
Ошибка: недостаточно информации для вывода параметра T в constructor Bookmarkable PageLink<T: Any!, C: Page!>(...)
item.queue(BookmarkablePageLink<>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, *>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, in WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, out WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, T : WebPage>("link", bookmark.page))
Это был бы "гипотетически правильный" способ сделать это в Javaish-talk (просто намерение, но это не настоящий код), но это не поддерживается Kotlin:
item.queue(BookmarkablePageLink<Any, ? extends WebPage>("link", bookmark.page))
Мое лучшее обходное решение - это, что уродливо, но работает:
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>))
Удивительно на Java это было просто:
item.queue(new BookmarkablePageLink<>("link", bookmark.getPage() ));
Ответы
Ответ 1
Я создаю ответ из всех лучших комментариев, потому что они уже кажутся очень ценными.
Обходной путь от вопроса - это уже хорошее начало:
BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>)
Также справедливо промежуточная переменная @AlexeyRomanov (или аналогичная промежуточная функция):
val link: BookmarkablePageLink<Any> = BookmarkablePageLink("link", bookmark.page)
Также ценным для всех, кто находит этот вопрос через Google, может быть краткий обзор обработки ошибок Kotlin vs Java с изменением типа, как описано в документации Kotlin:
- в Java обработка выполняется на сайте call-сайта с использованием подстановочных знаков (которые вы не можете использовать, поскольку сайт-колл находится в Котлине)
- и в Котлин обращение находится на сайте декларации, используя
in
и out
ключевых слов (которые вы не можете использовать, потому что ваше выражение в Java)
Кроме того, конструкторы Java на узле-вызове позволяют указывать только аргументы типа из класса, тогда как в Kotlin вызов конструктора имеет два аргумента типа: один из класса и другой из конструктора. Поэтому в Java мы должны сказать
new BookmarkablePageLink<T>("something", Page.class)
и в Котлине
BookmarkablePageLink<T, Page>("something", Page::class.java)
несмотря на то, что оба вызывали один и тот же конструктор с теми же аргументами.
Учитывая, что Котлин выбрал подход для типов вариантов, который является полной противоположностью Java, я по-прежнему счастлив, что нам нужны только обходные решения в стольких случаях. ;-)
Ответ 2
Насколько я понимаю, значение BookmarkablePageLink(...)
должно быть приблизительно эквивалентно new BookmarkablePageLink<>
в Java, поэтому это вариант, который должен "работать". Все остальные, которых вы пытались, не должны, каждый по разным причинам.
Конструкторы, у которых есть свои параметры типа, очень редки (перед тем, как увидеть этот вопрос, я думал, что они незаконны), поэтому их можно упустить где-то в компиляторе Kotlin. Возможное обходное решение заключается в том, чтобы сделать его функцией:
fun <T, C : Page> makeBookmarkablePageLink(id: String, clazz: Class<C>): BookmarkablePageLink<T> =
BookmarkablePageLink<T, C>(id, clazz)
а потом
item.queue(makeBookmarkablePageLink("link", bookmark.page))
Я также отмечу, что я уверен
"правильный" способ сделать это в Java-говорить
фактически неверно; и на самом деле вы не можете явно записывать параметры типа в Java, потому что параметр второго типа является захваченным подстановочным знаком.
Ответ 3
Пожалуйста, попробуй
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))