gpt4 book ai didi

generics - Kotlin:使用继承或泛型为不同的类重用一个函数

转载 作者:行者123 更新时间:2023-12-02 12:57:46 35 4
gpt4 key购买 nike

我正在 Kotlin 中做一个简单的项目,试图更好地学习这门语言,但我被困在一个特定的问题上。

该项目是一个简单的食谱管理应用程序,到目前为止,我只有食谱、配料和过敏的基本对象,以及用于存储它们集合的对象。

我已经决定我想要通过名称变量搜索食谱的选项。为此,我创建了一个函数,它在食谱商店中搜索食谱列表,并根据多个条件将结果添加到一个可变的食谱列表中,以确保列表的第一个元素是最相关的。

我能够做到这一点,但后来决定其他对象存储应该具有此功能,以便轻松搜索有关成分的信息,并提供添加一个简单的自动完成功能的选项,该功能在输入成分时返回相关建议配方创建用户界面。

由于搜索/过滤功能相当大,我想重新使用它,因为它对于每个对象都是相同的:获取一个 HashSet 和一个字符串,并返回一个过滤和排序的列表,例如给定一个 HashSet 和一个字符串,进行搜索并返回一个列表。

我正在努力制作一个像这样的通用函数,它可以采用我希望能够过滤的 3 种类型的对象中的任何一种,并返回该对象的列表。

我最初制作了一个 Utils 类,并在其中尝试使该函数采用泛型:

fun <T> sortObjectsBySearchRelevance(search: String, set: Set<T>): List<T> {
var orderedList = mutableListOf<T>()

set.forEach{
if(it.name == search) orderedList.add(it)
}

return orderedList
}

(实际的过滤/搜索代码要大得多,有很多 if else 和 forEach 语句,但为简单起见,我只包含了完全匹配的情况,因为排序功能在这里并不重要)

我意识到这样做时无法访问对象 T 的名称参数。

然后我创建了一个类“SearchableObject”,它总是有一个名称参数,并将其他类设置为扩展以扩展它,所以我可以将 sortObjectsBySearchRelevance 的参数类型设置为 SearchableObject,允许函数访问名称变量:
open class SearchableObject (open var name: String){


}
import common.SearchableObject

class Allergy(override var name: String = "Allery name not given") : SearchableObject(name){
override fun toString(): String {
return "Allergy(name='$name')"
}

}

可重复使用的搜索功能是:
fun sortObjectsBySearchRelevance(search: String, set: Set<SearchableObject>): List<SearchableObject> {
var orderedList = mutableListOf<SearchableObject>()

set.forEach{
if(it.name == search) orderedList.add(it)
}

return orderedList
}

但是在 AllergyStoreImpl 类中,搜索方法如下所示:
override fun autoSuggest(search: String): List<Allergy> {

val orderedList = utils.sortObjectsBySearchRelevance(search, allergies)
var orderedAllergyList = mutableListOf<Allergy>()
orderedList.forEach { if(it is Allergy) orderedAllergyList.add(it) }
return orderedAllergyList

我不得不添加一些额外的代码行来验证列表中的每个元素都是过敏症,然后将其添加到一个新列表中,然后我可以返回该列表。

有没有更简单或更优雅的方法来做到这一点?

我想让 Utils 类可用于其他类,其中包含一个公开可用的功能。该函数接受一个字符串和一组对象,该组将是所有 Recipe 对象、所有成分对象或所有 Allergy 对象。然后,该函数必须能够对集合中的对象执行操作(通过使用它们的“名称”参数,它们都将具有),然后返回该类型对象的列表。

例如接受一组食谱​​和字符串,返回有序的食谱列表。

最佳答案

通常,您将拥有 SearchableObject作为一个接口(interface),而不是一个类,因为它的契约不承担任何状态。这也允许实现类派生一些其他类。所以它会是:

interface SearchableObject {
val name: String
}

class Allergy(override var name: String = "Allery name not given") : SearchableObject {
/* ... */
}

至于过滤 Allergy 的实例在搜索结果中,您可以使用标准库函数 filterIsInstance<...>() :
override fun autoSuggest(search: String): List<Allergy> =
utils.sortObjectsBySearchRelevance(search, allergies).filterIsInstance<Allergy>()

为了能够通用地过滤特定类型的实例,请考虑使用 reified type parameter 定义通用函数。 (特别是在运行时使用类型参数进行类型检查的方式):
inline fun <reified T : SearchableObject> autoSuggestInstancesOf(search: String): List<T> = 
utils.sortObjectsBySearchRelevance(search, allergies).filterIsInstance<T>()

配合用法: autoSuggestInstancesOf<Allergy>("...") .您也可以使用 .filter { ... } 用于通过任何其他条件过滤结果列表,但请注意,它不会影响返回列表的推断元素类型(它仍然是 List<SearchableObjects> )。

关于generics - Kotlin:使用继承或泛型为不同的类重用一个函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57573008/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com