Как реализовать интерфейс Kotlin, который ссылается на соответствующий тип? - PullRequest
0 голосов
/ 27 сентября 2018

В интересах глупых мысленных экспериментов, основная цель которых состоит в том, чтобы изучить, как работает часть языка, я решил, что хочу исследовать способ сделать программистов на Python более комфортными в Котлине.Проще говоря, я могу сделать это, добавив:

class Foo {
    private val self:Foo get() = this
    ...
}

(в сторону Вопрос: существует ли более обобщенный способ ссылки на Foo в качестве возвращаемого типа, чтобы, если бы я изменил Foo на Bar, тип переменной self все равно будет ссылаться на «реализующий класс этого метода»?)

Хотя указывать эту строку в каждом классе, чтобы мы могли чувствовать себя эгоистично-питоническим, утомительно.Поэтому я обратился к интерфейсу.Сначала я хотел что-то вроде Self типа Swift для Protocols.Но я не мог найти ничего подобного в Котлине.Прочитав 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 ]

0 голосов
/ 02 октября 2018

По вашему предложению @DEADMC я выбрал глобальное расширение val вместо fun.Он не ответил на вопрос о том, как вы обычно ссылаетесь на соответствующий тип в реализации, не используя общий шаблон, но ДЕЙСТВИТЕЛЬНО решил большую проблему гораздо более простым и масштабируемым образом:

val <Anything>Anything.self:Anything inline get() = this
0 голосов
/ 28 сентября 2018

Я думаю, вы должны взглянуть на расширения .

Так что вы можете написать

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

...