Kotlin 等效于省略 TypeScript 实用程序类型
Kotlin equivalent of Omit TypeScript utility type
我在 Kotlin 中有两个非常相似的数据 类。唯一的区别是一个有ID字段,另一个没有(如果模型只存储在数据库中,则会生成ID)。
data class RouteWithId(
val id: String,
val name: String,
val description: String,
val comments: List<Comment>,
val media: List<Media>,
val points: List<RoutePoint>,
val userId: String,
val status: RouteState,
val tracks: List<TrackInfo>,
) {
enum class RouteState(val value: String){
IN_REVIEW("in-review"),
PUBLISHED("published");
}
}
data class Route(
val name: String,
val description: String,
val comments: List<Comment>,
val media: List<Media>,
val points: List<RoutePoint>,
val userId: String,
val status: RouteState,
val tracks: List<TrackInfo>,
) {
enum class RouteState(val value: String){
IN_REVIEW("in-review"),
PUBLISHED("published");
}
}
我试图用一个可为空的 id 字段统一它们,但很多时候,它只会产生很多噪音,因为我知道在几个地方,ID 会存在(从数据库加载后的任何后处理) .
我看到 TypeScript 有一个名为 Omit 的 utility type ,它可以用来从另一个类型派生出一个类型但省略了一些字段。
这对我的用例来说是完美的,因为我知道从数据库加载后该字段将存在,而在此之前我也知道它不会存在。
你知道如何在 Kotlin 中实现同样的事情吗?
Kotlin 中没有联合类型,但您可以使用继承来实现:
class Route(val name: String, val description: String, /* ... */) {
enum class RouteState(val value: String){
IN_REVIEW("in-review"),
PUBLISHED("published");
}
fun withId(id: Int): DBRoute = DBRoute(id, name, description, /* ... */)
}
class DBRoute(val id: Int, name: String, description: String, /* ... */) : Route(name, description) {
fun asRoute(): Route = Route(name, description, /* ... */)
}
这样,您可以将 Route
转换为 DBRoute
,反之亦然。这样做的缺点是您必须在 DBRoute
.
的构造函数中编写 Route
中的所有字段
我不知道它是否适合您,但您也可以使用 Map<Int, Route>
而无需创建新的 class,但这更适合 class 如果你需要一些操作来以某种方式包含 ID。
TLDR:您无法在 Object-Oriented 语言(如 Kotlin
.
中“正确地”实现您想要的
答案:
首先,让我们回顾一下 Object-Oriented 语言的原则之一:继承。 (See here for full ist of principles)
Inheritance. Relationships and subclasses between objects can be assigned, allowing developers to reuse a common logic while still maintaining a unique hierarchy. This property of OOP forces a more thorough data analysis, reduces development time and ensures a higher level of accuracy.
因此,根据继承的定义,subclass 没有选择继承什么的选项。这意味着,它必须继承其 parent class 的所有属性;它不能对继承什么挑剔。
例如,如果 parent class 有一个 Lung Cancer
属性,child class 也必须有 Lung Cancer
属性。 child class 不能说“呃,Lung Cancer
不好,所以我不想继承它!”。
其次,我们参考Kotlin中Data class
的定义。 (Definition of Data Class)
Kotlin 在 Data class
中设置了一个非常严格的规则,这样“数据 class 不允许有 child class 和 parent class”。这意味着,当您使用 Data Class
时,继承不适合。遗憾的是,如果你想在 Kotlin 中进行继承,你不能使用 Data Class
,只需使用普通的 class.
然而,如果你真的必须这样做,你可以通过 OOP“作弊”并利用 Kotlin 中的 abstract
和 interface
classes。 Apparent够了,这在 OOP 中是一个非常糟糕的做法。我建议您再次重新考虑您的建模系统。 (你考虑过在 kotlin 中使用 Optional
吗?)
这是我给你的例子:
//create an interface class that 'enforces ID'
interface HasID {
val id: Int
}
//Data Class must have ID
data class RouteWithId(val length: Int, override val id: Int) : HasID
//Data Class without ID
data class RouteWithOutId(val name: String)
如果您还有其他问题,请告诉我。谢谢
我在 Kotlin 中有两个非常相似的数据 类。唯一的区别是一个有ID字段,另一个没有(如果模型只存储在数据库中,则会生成ID)。
data class RouteWithId(
val id: String,
val name: String,
val description: String,
val comments: List<Comment>,
val media: List<Media>,
val points: List<RoutePoint>,
val userId: String,
val status: RouteState,
val tracks: List<TrackInfo>,
) {
enum class RouteState(val value: String){
IN_REVIEW("in-review"),
PUBLISHED("published");
}
}
data class Route(
val name: String,
val description: String,
val comments: List<Comment>,
val media: List<Media>,
val points: List<RoutePoint>,
val userId: String,
val status: RouteState,
val tracks: List<TrackInfo>,
) {
enum class RouteState(val value: String){
IN_REVIEW("in-review"),
PUBLISHED("published");
}
}
我试图用一个可为空的 id 字段统一它们,但很多时候,它只会产生很多噪音,因为我知道在几个地方,ID 会存在(从数据库加载后的任何后处理) .
我看到 TypeScript 有一个名为 Omit 的 utility type ,它可以用来从另一个类型派生出一个类型但省略了一些字段。
这对我的用例来说是完美的,因为我知道从数据库加载后该字段将存在,而在此之前我也知道它不会存在。
你知道如何在 Kotlin 中实现同样的事情吗?
Kotlin 中没有联合类型,但您可以使用继承来实现:
class Route(val name: String, val description: String, /* ... */) {
enum class RouteState(val value: String){
IN_REVIEW("in-review"),
PUBLISHED("published");
}
fun withId(id: Int): DBRoute = DBRoute(id, name, description, /* ... */)
}
class DBRoute(val id: Int, name: String, description: String, /* ... */) : Route(name, description) {
fun asRoute(): Route = Route(name, description, /* ... */)
}
这样,您可以将 Route
转换为 DBRoute
,反之亦然。这样做的缺点是您必须在 DBRoute
.
Route
中的所有字段
我不知道它是否适合您,但您也可以使用 Map<Int, Route>
而无需创建新的 class,但这更适合 class 如果你需要一些操作来以某种方式包含 ID。
TLDR:您无法在 Object-Oriented 语言(如 Kotlin
.
答案:
首先,让我们回顾一下 Object-Oriented 语言的原则之一:继承。 (See here for full ist of principles)
Inheritance. Relationships and subclasses between objects can be assigned, allowing developers to reuse a common logic while still maintaining a unique hierarchy. This property of OOP forces a more thorough data analysis, reduces development time and ensures a higher level of accuracy.
因此,根据继承的定义,subclass 没有选择继承什么的选项。这意味着,它必须继承其 parent class 的所有属性;它不能对继承什么挑剔。
例如,如果 parent class 有一个 Lung Cancer
属性,child class 也必须有 Lung Cancer
属性。 child class 不能说“呃,Lung Cancer
不好,所以我不想继承它!”。
其次,我们参考Kotlin中Data class
的定义。 (Definition of Data Class)
Kotlin 在 Data class
中设置了一个非常严格的规则,这样“数据 class 不允许有 child class 和 parent class”。这意味着,当您使用 Data Class
时,继承不适合。遗憾的是,如果你想在 Kotlin 中进行继承,你不能使用 Data Class
,只需使用普通的 class.
然而,如果你真的必须这样做,你可以通过 OOP“作弊”并利用 Kotlin 中的 abstract
和 interface
classes。 Apparent够了,这在 OOP 中是一个非常糟糕的做法。我建议您再次重新考虑您的建模系统。 (你考虑过在 kotlin 中使用 Optional
吗?)
这是我给你的例子:
//create an interface class that 'enforces ID'
interface HasID {
val id: Int
}
//Data Class must have ID
data class RouteWithId(val length: Int, override val id: Int) : HasID
//Data Class without ID
data class RouteWithOutId(val name: String)
如果您还有其他问题,请告诉我。谢谢