2016-02-10 3 views
5

У меня есть существующий класс с методом экземпляра buildHierarchyUncached, подпись которого может быть найдена ниже.Функция Memoization В Kotlin

private fun buildHierarchyUncached(date: LocalDate): Node { ... } 

Я хотел бы предоставить публичный функции buildHiearchy, которая является memoized версии buildHierarchyUncached. Я могу приблизиться к тому, что я хочу:

val buildHiearchy = Memoize<LocalDate, Node>({buildHierarchy(it)}) 

который можно назвать как:

hierarchyService.buildHiearchy(businessDate) 

Использование:

class Memoize<I, O>(val func: (I) -> O): (I) -> O{ 
    val cache = hashMapOf<I, O>(); 
    override fun invoke(p1: I): O { 
    return cache.getOrPut(p1, { func(p1) }) 
    } 
} 

Я хотел бы иметь возможность объявить memoized функцию функция вместо свойства, которая не является огромной сделкой, хотя я считаю, что она помогает читаемости. Как это:

fun buildHierarchy(date: LocalDate): Node = Memoize<LocalDate, Node>({ buildHierarchyUncached(it)}) 

но что не компилируется: ". Тип рассогласования Обязательный узел Found memoize."

Кроме того, почему это не компилируется?

val buildHiearchy = Memoize<LocalDate, Node>({(date) -> buildHierarchy(date)}) 
+0

Для вещей, которые имеют ошибки компилятора, приятно включить сообщение об ошибке из компилятора, чтобы другие могли искать/находить этот вопрос. –

+0

Добавлена ​​ошибка компиляции, которую я получал. –

ответ

4

По характеру проблемы, вам нужно поле класса для хранения кэша (кэшированное значения или объекта кэширования или делегата). Таким образом, вы должны объявить val в классе где-то, поскольку функции не могут этого сделать.

Обратите внимание, что при объявлении вашего значения buildHiearchy, вы получите две вещей в одном: вы храните Memoize<..>(..) объект в поле класса, и вы получите invoke() функцию (объявивших где-то еще, но все же ..). Я не знаю, как вы можете объявить функцию и получить полевое хранилище без дополнительного синтаксиса.

Фрагмент кода использует устаревший синтаксис. Исправить это (без круглых скобок):

val buildHiearchy = Memoize<LocalDate, Node>({date -> buildHierarchy(date)}) 
+0

Ответ Elias использует закрытие и не требует класса. Ваш фрагмент отвечает на мой второстепенный вопрос, но не затрагивает мой главный вопрос. Я отредактировал вопрос, чтобы сделать реальный вопрос более ясным. А именно, как я могу объявить memoized funcion как функцию вместо свойства. –

+0

ну, это моя точка - у вас не может быть такой функции без поля где-то – voddan

1

Следующее решение работает для функций с одним аргументом. Если вы хотите, чтобы создали кэшированную версию функции bar вы просто объявить его как это:

val cachedBar = makeFunctionCache({ bar(it) }) 

об осуществлении хранит кэш в затворе, так что вам не нужно положить его в специальном классе:

fun <X, R> makeFunctionCache(fn: (X) -> R): (X) -> R { 
    val cache: MutableMap<X, R> = HashMap() 
    return { 
     cache.getOrPut(it, { fn(it) }) 
    } 
} 
+0

Возможно, это было непонятно из моего вопроса. Но я хотел бы объявить cachedBar как функцию, например: 'fun cachedBar (date: LocalDate): Node = makeFunctionCache ({date -> bar (date)})' –

+0

Не могли бы вы изменить свой вопрос и объяснить более подробно, что именно вам нужно делать? Мне непонятно, почему решение о закрытии не сработает.Похоже, и работает, как любая другая функция. Существуют различия, если функция фактически является частью интерфейса, но больше информации было бы полезно. –

Смежные вопросы