科特林数据类的成员函数的记忆化
在以下科特林例如,我想“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不支持记忆。当然,您可以编写自己的记忆功能或使用库https://github.com/MarioAriasC/funKTionale
使用funKTionale,我不必编写自己的memoization函数,来到这个解决方案。不幸的是,看起来 “boilerplatey”:
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
,所以您可以直接在您的数据类中公开函数属性,而不是创建另一个调用它的函数。最后,我删除了一些编译器可以推断的类型。
非常感谢@marstran,我学到了很多! – Peti
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()
,那么这里是一个简单的答案
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())
})
}
}
记忆是指缓存结果吗? – Joshua
@Joshua,是的。感谢您的评论。我编辑了这个问题,并添加了“缓存结果”。 – Peti