我正在尝试学习如何创建一个不可变的持久列表。现在我的实现是在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)的语言很新,所以我不能掌握所有这些。
提前致谢!
答案 0 :(得分:1)
问题是Java无法推断empty()
方法的类型参数。它放弃并假定它是Object
。 EmptyList<Object>
无法投放到IPersistentList<T>
要解决此问题,您可以明确传递它:
PersistentList<T> p = new PersistentList<T>(head, PersistentList.<T>empty(), 1);
将empty()
提取到临时局部变量:
IPersistentList<T> empty = PersistentList.empty();
PersistentList<T> p = new PersistentList<T>(head, empty, 1);
或使用Java 8,它应该能够处理这种情况。
请点击此处了解详情:http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html#target_types