Как реализовать интерфейс 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
Другие вопросы по тегам