在下面的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&lt; = 1.1不支持memoization。当然,您可以编写自己的记忆功能或使用像https://github.com/MarioAriasC/funKTionale
使用funKTionale,我不必编写自己的memoization函数,而是来到这个解决方案。不幸的是它看起来像“样板”:
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?
}
但是,如何实现这个目标?
答案 0 :(得分:2)
你可以从你的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-function在密钥中使用它们来查找答案,但这是无用的,因为它们永远不会改变(因为它们是用val
定义的)。
此外,由于matches
的类型为(String) -> Boolean
,因此您可以直接在数据类中公开函数属性,而不是创建另一个调用它的函数。最后,我删除了编译器可以推断的一些类型。
答案 1 :(得分:1)
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())
})
}
}