如何使 Java 中我自己的通用功能列表实现行为协变?
How do I make my own generic functional list implementation in Java behave covariantly?
我在Java中实现自己的链表主要是为了学习语法。我在 Scala 中有一些经验,并且正在尝试实现一个功能性的、不可变的链表。我无法理解如何制作协变串联方法。我希望能够将 List<Sub>
与 List<Super>
.
连接(附加)
public abstract List<T> {
public abstract T head();
public abstract List<T> tail();
public abstract boolean isEmpty();
// ... more methods
public List<T> concat(List<? extends T> that) {
if (this.isEmpty()) return (List<T>) that; // Gross
else return new Cons<>(this.head(), this.tail().concat(that));
}
}
public class Cons<T> extends List<T> {
private final T head;
private final List<T> tail;
public boolean isEmpty() {return false;}
public Cons(T head, List<T> tail) {this.head = head; this.tail = tail;}
public T head() {return head;}
public List<T> tail() {return tail;}
}
public class Nil<T> extends List<T> {
public T head() {throw new NoSuchElementException();}
public List<T> tail() {throw new NoSuchElementException();}
public boolean isEmpty() {return true;}
}
我似乎只能通过将子类型列表显式转换为看起来很丑陋的超类型列表来做到这一点。我本质上是在尝试模仿 Scala 的 List[+T]
协方差形式。干杯。
就 Java 而言,List<Subclass>
不是 List<Superclass>
,除此之外别无他法。不支持协变和逆变。
我可以想到几个选项:
- 将
concat
声明为 returning List<? extends T>
,而不是承诺它将 return 完全 List<T>
。
- 做你正在做的事 — 你知道,因为你的
List
class 是不可变的,所以重新解释 List<Subclass>
作为 List<Superclass>
,所以你可以直接转换它,加上适当的 @SuppressWarnings
注释和注释。 (您可能希望将其集中在私有 upcast
方法中。)
- 将
Cons.tail
声明为 List<? extends T>
类型,并且每当您需要从 List<? extends Superclass>
转换为 List<Superclass>
时,您都可以通过解构和重构来实现——创建一个具有相同字段的新 Cons<Superclass>
或 Nil<Superclass>
。 (将 Cons.tail
声明为 List<? extends T>
的原因是您不需要复制整个列表,而只需复制第一个缺点。)(与 #2 一样,您可能想要将其集中在私有 upcast
方法中,Nil
和 Cons
都可以适当地实现。)
我在Java中实现自己的链表主要是为了学习语法。我在 Scala 中有一些经验,并且正在尝试实现一个功能性的、不可变的链表。我无法理解如何制作协变串联方法。我希望能够将 List<Sub>
与 List<Super>
.
public abstract List<T> {
public abstract T head();
public abstract List<T> tail();
public abstract boolean isEmpty();
// ... more methods
public List<T> concat(List<? extends T> that) {
if (this.isEmpty()) return (List<T>) that; // Gross
else return new Cons<>(this.head(), this.tail().concat(that));
}
}
public class Cons<T> extends List<T> {
private final T head;
private final List<T> tail;
public boolean isEmpty() {return false;}
public Cons(T head, List<T> tail) {this.head = head; this.tail = tail;}
public T head() {return head;}
public List<T> tail() {return tail;}
}
public class Nil<T> extends List<T> {
public T head() {throw new NoSuchElementException();}
public List<T> tail() {throw new NoSuchElementException();}
public boolean isEmpty() {return true;}
}
我似乎只能通过将子类型列表显式转换为看起来很丑陋的超类型列表来做到这一点。我本质上是在尝试模仿 Scala 的 List[+T]
协方差形式。干杯。
就 Java 而言,List<Subclass>
不是 List<Superclass>
,除此之外别无他法。不支持协变和逆变。
我可以想到几个选项:
- 将
concat
声明为 returningList<? extends T>
,而不是承诺它将 return 完全List<T>
。 - 做你正在做的事 — 你知道,因为你的
List
class 是不可变的,所以重新解释List<Subclass>
作为List<Superclass>
,所以你可以直接转换它,加上适当的@SuppressWarnings
注释和注释。 (您可能希望将其集中在私有upcast
方法中。) - 将
Cons.tail
声明为List<? extends T>
类型,并且每当您需要从List<? extends Superclass>
转换为List<Superclass>
时,您都可以通过解构和重构来实现——创建一个具有相同字段的新Cons<Superclass>
或Nil<Superclass>
。 (将Cons.tail
声明为List<? extends T>
的原因是您不需要复制整个列表,而只需复制第一个缺点。)(与 #2 一样,您可能想要将其集中在私有upcast
方法中,Nil
和Cons
都可以适当地实现。)