Методы-члены-памятники в Groovy - PullRequest
4 голосов
/ 02 апреля 2012

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

foo = {…}.memoize()

Однако я не могу найти способ запоминания метода-члена. Есть ли способ сделать это?

Ответы [ 2 ]

7 голосов
/ 03 апреля 2012

Edit:

В Groovy 2.2.X будет новое преобразование AST с именем @Memoized, которое сделает это за вас.

import groovy.transform.Memoized

class Woo {
  @Memoized
  def sum( int a, int b ) {
    Thread.sleep( 1000 )
    a + b
  }
}

new Woo().with {
  println new Date()
  println sum( 1, 2 )
  println new Date()
  println sum( 1, 2 )
  println new Date()
}

Оригинальный ответ

Другим вариантом было бы написать какое-то преобразование AST, чтобы позволить вам аннотировать метод с помощью @Memoize и сделать для вас памятку.

Я могу найти пару примеров, один здесь для добавления Redis в качестве кэша Memoization к Grails , и другой здесь, который, кажется, позволяет запоминать методы с одним аргументом путем в основном манипулирования AST выглядит как вторая часть ответа эпидемиолога.

Поскольку вам, вероятно, нужны несколько параметров, я бы выбрал второй метод эпидемиолога. Однако написание преобразования AST может быть интересным экспериментом / побочным проектом?

Это то, что, если все сделано правильно, я могу увидеть возвращение в исходный код ядра Groovy (для славы и славы): -)

3 голосов
/ 02 апреля 2012

Я не знаю ни одного прямого способа запоминания методов, как вы можете запоминать Закрытие.

Если метод не получает никаких параметров (и, следовательно, возвращаемое значение всегда одинаково, поскольку оно является чистым), вы можете сделать запоминание, просто сохранив возвращаемое значение в атрибуте члена. Этот метод очень распространен в Ruby и обычно принимает форму def some_method; @value ||= compute_value; end. Переводя это в Groovy, вы можете сделать что-то вроде:

class Computer {
    private answer
    def getAnswer() {
        answer = answer ?: computeAnswer()
    }
    private computeAnswer() {
        println "Computing the Answer to the Ultimate Question of Life, the Universe, and Everything"
        42
    }
}

def c = new Computer()
println c.answer
println c.answer

Вывод:

Computing the Answer to the Ultimate Question of Life, the Universe, and Everything
42
42

Так что памятка сработала:)

Если вы не хотите определять дополнительный метод, вы также можете написать метод getAnswer, например:

def getAnswer() {
    if (answer != null) return answer
    println "Computing the Answer to the Ultimate Question of Life, the Universe, and Everything"
    answer = 42        
}

Теперь, если метод действительно получает какие-либо параметры, было бы весьма неудобно осуществлять запоминание таким способом. Вместо этого вы можете вызвать запомненное закрытие из того метода, который вы хотите запоминать:

class Calculator {
    def sum(a, b) {
        memoizedSum(a, b)
    }
    private memoizedSum = { a, b ->
        println "Computing the sum of $a and $b"
        a + b
    }.memoize()
}

def c = new Calculator()
println c.sum(4, 7)
println c.sum(4, 7)
println c.sum(4, 2)

Вывод:

Computing the sum of 4 and 7
11
11
Computing the sum of 4 and 2
6
...