【发布时间】:2014-07-05 22:30:37
【问题描述】:
我正在尝试学习如何创建一个不可变的持久列表。现在我的实现是在 java 中,虽然我对这个概念更感兴趣,并弄清楚如何很好地使用静态类型。
我的第一个实现是有效的。它有final int size、final T head 和final PersistentList<T> tail 字段。它只是一个单向链表,每个节点指向另一个相同PersistentList<T> 类型的节点(通过tail 字段),或者在链表末尾的情况下指向null。这就是问题所在,我不想到处检查null,也不想使用null 来表示列表结尾/空列表。我想用一个新的EmptyList 对象来表示一个空列表,它总是 是我的 PersistentList 抽象类中的最后一个节点。这就是 clojure does 和 Eric Lippert demonstrated(在 C# 中)。
我的问题是,由于这个新的 EmptyList 对象属于不同的类型,我在在正确的位置指定正确的类型时遇到问题,编译器会抱怨。
我创建了一个抽象类IPersistentList,并从中派生了PersistentList 和EmptyList。目标是具有以下列表结构:
|PersistentList<T>| --> |PersistentList<T>| --> |EmptyList<T>|
现在像tail 或静态create 函数这样的方法需要能够返回PersistentList<T> 或EmptyList<T> 实例,具体取决于它是否是列表中的最后一个节点,但我该如何指定正确的返回类型?我的猜测是总是返回父抽象类的类型IPersistentList<T>。但这要求我总是强制转换派生类,这感觉非常肮脏,编译器仍在抱怨。我也不想要需要客户端代码来初始化类型列表然后必须强制转换的解决方案。我希望它是透明的。
这是我的代码的gist。这是错误:
persistent_list/src/main/java/com/benreinhart/persistentlist/PersistentList.java:15: error: constructor PersistentList in class PersistentList<T#2> cannot be applied to given types;
PersistentList<T> p = new PersistentList<T>(head, PersistentList.empty(), 1);
^
required: T#1,IPersistentList<T#1>,int
found: T#1,IPersistentList<Object>,int
reason: actual argument IPersistentList<Object> cannot be converted to IPersistentList<T#1> by method invocation conversion
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>create(T#1)
T#2 extends Object declared in class PersistentList
Note: persistent_list/src/main/java/com/benreinhart/persistentlist/PersistentList.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error
如您所见,编译器抱怨我尝试将 EmptyList<T> 转换为 IPersistentList<T>。
一般来说,在给定静态类型约束的情况下,我将如何做这样的事情?无论如何,如果是这样,我可以在不到处铸造的情况下做到这一点吗?我尽力遵循其数据结构的 clojure 源代码,但那里还有很多其他东西,而且我对静态类型(和 java)的语言很陌生,所以我无法掌握所有它。
提前致谢!
【问题讨论】:
标签: java list persistent typing