Можно ли создать рекурсивный тип функции в Kotlin?
у меня есть функции, которые представляют собой шаги в процессе. Каждая функция также знает следующий шаг, если он есть. Я хотел бы иметь возможность сделать что-то вроде:
fun fooStep() : Step? {
... do something ...
return ::barStep // the next step is barStep
}
эти функции вызываются из Центральной диспетчерской функции, которая содержит код примерно так:
var step = startStep
while (step != null) {
step = step()
}
обратите внимание, что логика на определенном шаге также определяет следующий шаг, если оно вообще существует.
Я думал, что смогу определить Step
as:
typealias Step = () -> Step?
так Step
- это функция, которая возвращает другой Step
, или null. Однако это не удается скомпилировать с помощью:
Kotlin: Recursive type alias in expansion: Step
Я могу обойти это, обернув функцию в объект. например:
data class StepWrapper(val step: () -> StepWrapper?)
и изменение сигнатур моей функции соответственно.
к сожалению, это означает, что я не могу просто использовать функции литералы (например: ::barStep
), но вместо этого нужно обернуть их в StepWrapper
:
fun fooStep() : StepWrapper? {
... do something ...
return StepWrapper(::barStep)
}
(Я тоже соответственно, я должен изменить цикл отправки.)
Я хотел бы избежать необходимости создавать эти объекты-оболочки, если это возможно. Есть ли способ сделать это в Котлине?
3 ответов
вы можете определить его, используя некоторый общий интерфейс:
interface StepW<out T> : ()->T?
interface Step : StepW<Step>
class Step1 : Step {
override fun invoke(): Step? = Step2()
}
class Step2 : Step {
override fun invoke(): Step? = null
}
здесь Step
ваш тип рекурсивной функции.
вот как вы можете заставить его работать, хотя я очень не уверен, что вы пытаетесь достичь с его помощью:
typealias Fun<T> = () -> T
typealias Step<T> = () -> (T)
typealias Step1 = Step<Fun<Step2>>
typealias Step2 = Step<Fun<Step3>>
typealias Step3 = Step<Unit>
fun step1(): Step1 {
return {
println("step 1")
::step2
}
}
fun step2(): Step2 {
return {
println("step 2")
::step3
}
}
fun step3(): Step3 {
return { println("done") }
}
использовать перечисление реализовать шаблон состояния с конечными состояниями и предпочитают возвращать ненулевые значения. Перечисление может наследовать функцию.
enum class Step : () -> Step {
Step1 {
override fun invoke() = Step2
},
Step2 {
override fun invoke() = End
},
End {
override fun invoke() = this
}
}
fun work() {
var step = Step.Step1
while (step !== Step.End) {
step = step()
}
}