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中数据类的name
和description
,所以您不必将它们作为参数传递。 把它们作为参数可以使memoize函数在关键字中使用它们来查找答案,但这是无用的,因为它们永远不会改变(因为它们是用val
定义的)。
另外,因为matches
的类型是(String) -> Boolean
,所以你可以直接在你的数据类中公开函数属性,而不是创建另一个调用它的函数。 最后,我删除了一些编译器可以推断的类型。
a
和b
是val
,所以你可以把结果赋值给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()) }) } }