Как реализовать интерфейс Kotlin, который ссылается на соответствующий тип?
В интересах глупых мысленных экспериментов, основная цель которых состоит в том, чтобы исследовать, как работает часть языка, я решил, что хочу исследовать способ сделать программистов на Python более комфортными в Котлине. Проще говоря, я могу сделать это, добавив:
class Foo {
private val self:Foo get() = this
...
}
(Помимо вопроса: существует ли более обобщенный способ обращения к Foo
как тип возврата там, так что если я изменил Foo
в Bar
тип переменной self
все равно будет ссылаться на "реализацию класса этого метода"?)
Однако необходимость помещать эту строку в каждом классе, чтобы мы могли чувствовать себя эгоистично-питоническими, утомительна. Поэтому я обратился к интерфейсу. То, что я изначально хотел, это что-то вроде Swift's Self
тип для протоколов. Но я не мог найти ничего подобного в Котлине. Прочитав https://kotlinlang.org/docs/reference/generics.html (который, по-видимому, относится и к Java, и к Kotlin), я пришел к выводу, что, возможно, "Декларация сайта декларации" для меня:
interface Selfish<out T> {
val self:T get() = this as T
}
class Foo:Selfish<Foo> {
}
Это лучше. Нежелательно, чтобы я дважды указывал имя класса в объявлении, но я не думаю, что есть способ обойти это. Есть?
Кроме того, это работает для конечных классов, но если я хочу иметь иерархию классов, которая соответствует Selfish на корневом уровне, вещи рушатся:
class Foo:Selfish<Foo> { ... }
class Bar:Foo { ... }
Методы в баре, которые используют self
имеют неправильный тип. И добавление , Selfish<Bar>
создает конфликт.
Есть ли инструмент, который я еще не обнаружил, чтобы заставить тип ссылаться на унаследованный тип?
Есть ли другой подход (кроме интерфейсов) сделать что-то подобное?
Неужели я сделал неправильный выбор, используя "Объявление отклонений сайта"?
2 ответа
Я думаю, вы должны взглянуть на расширения.
Так что вы можете написать
fun <T>Foo.getSelf(): T {
return this as T
}
Тогда, если у вас есть
open class Foo
class Bar: Foo()
так
Bar().getSelf<Bar>()
вернет объект Bar
учебный класс
Или даже проще, вы можете написать
fun <T:Foo>T.getSelf(): T {
return this as T
}
так что вы можете просто позвонить
Bar().getSelf()
получить экземпляр любого класса, расширенного из Foo
По вашему предложению @DEADMC, я пошел с глобальным расширением val
в отличие от fun
, Он не ответил на вопрос о том, как вы обычно ссылаетесь на соответствующий тип в реализации, не используя общий шаблон, но ДЕЙСТВИТЕЛЬНО решил большую проблему гораздо более простым и масштабируемым способом:
val <Anything>Anything.self:Anything inline get() = this