Kotlin数据类成员函数的记忆

在下面的Kotlin示例中,我想“memoize”(缓存结果)成员函数matches

 import java.util.regex.Pattern data class MyDataClass(val name: String = "John Doe", val description: String = "Famous person") { //TODO memoize this fun matches(searchTerm: String): Boolean { println("Calculating...") return name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) } } fun main(args: Array<String>) { val myData = MyDataClass() println(myData.matches("John")) println(myData.matches("John")) println(myData.matches("John")) println(myData.matches("Famous")) println(myData.matches("Famous")) println(myData.matches("Famous")) } 

据我所知,Kotlin <= 1.1不支持记忆。 当然,你可以编写自己的memoization函数或者使用像https://github.com/MarioAriasC/funKTionale这样的库

使用funKTionale,我不必编写我自己的记忆功能,来到这个解决方案。 不幸的是它看起来是“板甲”:

 import org.funktionale.memoization.memoize import java.util.regex.Pattern data class MyMemoizedDataClassV1(val name: String = "John Doe", val description: String = "Famous person") { private val memoizedMatches: (String, String, String) -> Boolean = { name: String, description: String, searchTerm: String -> println("Calculating...") name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) }.memoize() fun matches(searchTerm: String): Boolean { return memoizedMatches(name, description, searchTerm) } } fun main(args: Array<String>) { val myData = MyMemoizedDataClassV1() println(myData.matches("John")) println(myData.matches("John")) println(myData.matches("John")) println(myData.matches("Famous")) println(myData.matches("Famous")) println(myData.matches("Famous")) } 

我想像一个更好看的解决方案

 data class MyDataClass(val name: String = "John Doe", val description: String = "Famous person") { fun matches(searchTerm: String): Boolean { println("Calculating...") return name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) }.memoize() //TODO how? } 

但是,如何实现呢?

您可以从Funktionale代码中删除大量的样板文件:

 data class MyMemoizedDataClassV1(val name: String = "John Doe", val description: String = "Famous person") { val matches = { searchTerm: String -> println("Calculating...") name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) }.memoize() } 

您可以访问lambda中数据类的namedescription ,所以您不必将它们作为参数传递。 把它们作为参数可以使memoize函数在关键字中使用它们来查找答案,但这是无用的,因为它们永远不会改变(因为它们是用val定义的)。

另外,因为matches的类型是(String) -> Boolean ,所以你可以直接在你的数据类中公开函数属性,而不是创建另一个调用它的函数。 最后,我删除了一些编译器可以推断的类型。

abval ,所以你可以把结果赋值给val

 data class MyDataClass(val a: Int = 1, val b: Int = 2) { val sum = a + b } 

如果计算成本很高,可以使用懒惰来延迟计算。

 data class MyDataClass(val a: Int = 1, val b: Int = 2) { val sum: Int by lazy { a + b } } 

编辑:编辑问题的新答案

 interface StringMatchable { fun matches(searchTerm: String): Boolean } data class MyDataClass(val name: String = "John Doe", val description: String = "Famous person") : StringMatchable by CacheStringMatchable({ searchTerm -> name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) }) class CacheStringMatchable(private val function: (String) -> Boolean) : StringMatchable { private val map: MutableMap<String, Boolean> = mutableMapOf() override fun matches(searchTerm: String): Boolean { return map.computeIfAbsent(searchTerm, function) } } 

要委托一个方法,目前只能通过接口进行。 所以,它可能不能用通用的方式写(即1个缓存类)。

Edit2:如果这是唯一需要matches()matches() ,那么这里是一个更简单的答案

 data class MyDataClass(val name: String = "John Doe", val description: String = "Famous person") { private val map: MutableMap<String, Boolean> = mutableMapOf() fun matches(searchTerm: String): Boolean { return map.computeIfAbsent(searchTerm, { searchTerm -> name.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) || description.matches("(?i).*${Pattern.quote(searchTerm)}.*".toRegex()) }) } }