2

我一直在探索 Kotlin,并编写了一个小程序/脚本来完成我觉得无聊的任务。

在程序开发中,我使用数据类来表示播放列表。在设计的某一时刻,我想要一种特殊的类型PlaylistEmptyPlaylist.

我无法让它工作。

您将如何与 Kotlin 建立这种关系?

在 Java 中,我只是扩展Playlist(或者可能为它们创建一个接口/抽象类来继承)。

我只是想能够拥有一个List<Playlist>而不是List<Playlist?>

最后我只是创建了一个Playlist对象,但我对是否可以使用数据类创建 IS-A 层次结构感兴趣。

4

1 回答 1

4

UPD:Kotlin Beta 添加了对data类的限制,因此答案也已更新。

  • 数据类不能是抽象的、开放的、密封的或内部的;
  • 数据类不能扩展其他类(但可以实现接口)。

因此,构建其层次结构的唯一选择是接口。此限制可能会在未来的版本中发布。


根据您的说法,继承EmptyPlaylistPlaylistwhich 被假定为非空的想法看起来有点矛盾,但有一些选择:

  • 您可以同时制作TracksPlaylistEmptyPlaylist实现一些Playlist接口。这是合理的,因为EmptyPlaylist可能不包含 aPlaylist所做的一切。这看起来像:

    public interface Playlist
    
    data class TracksPlaylist(val name: String, val tracks: List<Track>) : Playlist
    data class EmptyPlaylist(val name: String): Playlist
    
  • 如果您甚至不希望EmptyPlaylist存在多个实例,则可以将其设为一个val而不是不同的类并避免 is-checks,只是比较

    val EMPTY_PLAYLIST = TracksPlaylist("EMPTY", listOf())
    

    这适用于空播放列表都相等的情况,因此单个对象足以代表它们。

  • 您可以使用sealed。这不允许您使用data类,但sealed类可能适合构建这样的类层次结构。

    sealedclass 是一个抽象类,只能在其主体内声明其子类。这使编译器保证这些是唯一的子类。例子:

    sealed class Playlist(val name: String) {
        class Tracks(name: String, val tracks: List<Track>): Playlist(name)
        class Playlists(name: String, val innerPlaylists: List<Playlist>): Playlist(name)
        object Empty: Playlist("EMPTY")
    }
    

    之后,如果您声明了密封类的所有子类和对象,您将能够在不指定分支的情况下使用when语句:else

    when (p) {
        is Playlist.Tracks -> { /* ... */ }
        is Playlist.Playlists -> { /* ... */ }
        Playlist.Empty -> { /* ... */ }
    }
    

    但是,如果需要,此选项需要您自己处理equalshashCodetoString和。copycomponentN

于 2015-08-22T02:49:38.203 回答