我如何在Java中实现自己的通用功能列表实现协变?

发布于 2025-01-24 14:28:12 字数 1227 浏览 2 评论 0原文

我主要是在Java中实现自己的链接列表,主要是为了学习语法。我在Scala有一些经验,并且正在尝试实现功能性,不可变的链接列表。我很难理解如何制作协变量的串联方法。我希望能够与(to)a list< super>相连(附加)a list< sub>

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的列表[+T]协方差形式主义。干杯。

I am implementing my own linked list in Java mainly as an attempt to learnt the syntax. I have some experience in Scala, and am trying to implement a functional, immutable linked list. I'm having trouble understanding how to make a covariant concatenation method. I want to be able to concatenate (append) a List<Sub> with (to) a 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;}
}

I seem to only be able to do this by explicitly casting the list of subtypes to a list of supertypes which seems ugly. I'm essentially trying to mimic Scala's List[+T] covariance formalism. Cheers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝颜夕 2025-01-31 14:28:12

就java而言,list&lt; subclass&gt;不是list&lt; superClass&gt;,否则就没有办法告诉它。不支持协方差和违反。

我可以在这里想到一些选项:

  1. 声明concat作为返回list&lt;?扩展了T&gt;,而不是承诺它将完全返回list&lt; t&gt;
  2. 做自己正在做的事情 - 知道,由于您的list类是不可变的,因此可以安全地重新诠释list&lt; subclass&gt;作为一个list&lt; superClass&gt;,因此您可以施放它,再加上适当的@suppresswarnings带有注释的注释。 (您可能需要将其集中在私有upcast方法中。)
  3. 声明cons.tail为具有类型list&lt;?扩展了T&gt;,并且只要您需要从列表转换时?将superclass&gt;扩展到list&lt; superClass&gt;,您可以通过破坏和重建来做到这一点 - 创建一个新的cons&lt&lt; superclass&gt; or ; 具有相同的字段。 (声明cons.tail列表&lt;? )(与#2一样,您可能需要将其集中在私有upcast方法中,nil and cons每个人都可以适当地实现)

As far as Java is concerned, a List<Subclass> isn't a List<Superclass>, and there's no way to tell it otherwise. Neither covariance nor contravariance is supported.

I can think of a few options here:

  1. Declare concat as returning List<? extends T>, rather than promising that it will return exactly List<T>.
  2. Do what you're doing — you know that, since your List class is immutable, it's safe to reinterpret a List<Subclass> as a List<Superclass>, so you can just cast it, plus an appropriate @SuppressWarnings annotation with a comment. (You'll probably want to centralize this in a private upcast method.)
  3. Declare Cons.tail as having type List<? extends T>, and whenever you need to convert from List<? extends Superclass> to List<Superclass>, you can do so by destructuring and reconstructing — creating a new Cons<Superclass> or Nil<Superclass> with the same fields. (The reason to declare Cons.tail as List<? extends T> is so that you don't need to copy the whole list over, but just the first cons.) (As with #2, you'll probably want to centralize this in a private upcast method, which Nil and Cons can each implement appropriately.)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文