当前位置: 首页 > 面试题库 >

Java标记的联合/和类型

贲言
2023-03-14
问题内容

有什么方法可以在Java中定义求和类型?Java似乎自然地直接支持产品类型,我认为枚举可能允许它支持求和类型,而继承看起来也许可以做到,但是至少有一种情况我无法解决。详细地说,求和类型是可以恰好具有一组不同类型之一的类型,例如C中的标记联合。就我而言,我正在尝试在Java中实现haskell的Either类型:

data Either a b = Left a | Right b

但在基本级别上,我必须将其实现为产品类型,而忽略其字段之一:

public class Either<L,R>
{
    private L left = null;
    private R right = null;

    public static <L,R> Either<L,R> right(R right)
    {
        return new Either<>(null, right);
    }

    public static <L,R> Either<L,R> left(L left)
    {
        return new Either<>(left, null);
    }

    private Either(L left, R right) throws IllegalArgumentException
    {
        this.left = left;
        this.right = right;
        if (left != null && right != null)
        {
            throw new IllegalArgumentException("An Either cannot be created with two values");
        }
        if (left == right)
        {
            throw new IllegalArgumentException("An Either cannot be created without a value");
        }
    }

    .
    .
    .
}

我尝试通过继承来实现,但是我必须使用通配符类型参数或等效参数,Java泛型不允许使用:

public class Left<L> extends Either<L,?>

我没有太多使用Java的Enums,但是尽管它们似乎是次佳的候选者,但我并不抱有希望。
在这一点上,我认为只有通过类型转换Object值才有可能做到这一点,我希望完全避免这种情况,除非有一种方法可以安全,一次性地对所有求和类型使用它。


问题答案:

制作Either一个没有字段且只有一个构造函数(私有,无参数,空)的抽象类,并将您的“数据构造函数”(leftright静态工厂方法)嵌套在该类中,以便他们可以看到私有构造函数,而其他则不能有效密封型。

使用抽象方法either来模拟详尽的模式匹配,并适当地覆盖静态工厂方法返回的具体类型。实现方便的方法(如fromLeftfromRightbimapfirstsecond而言)either

import java.util.Optional;
import java.util.function.Function;

public abstract class Either<A, B> {
    private Either() {}

    public abstract <C> C either(Function<? super A, ? extends C> left,
                                 Function<? super B, ? extends C> right);

    public static <A, B> Either<A, B> left(A value) {
        return new Either<A, B>() {
            @Override
            public <C> C either(Function<? super A, ? extends C> left,
                                Function<? super B, ? extends C> right) {
                return left.apply(value);
            }
        };
    }

    public static <A, B> Either<A, B> right(B value) {
        return new Either<A, B>() {
            @Override
            public <C> C either(Function<? super A, ? extends C> left,
                                Function<? super B, ? extends C> right) {
                return right.apply(value);
            }
        };
    }

    public Optional<A> fromLeft() {
        return this.either(Optional::of, value -> Optional.empty());
    }
}

愉快而安全!没有办法把它搞砸。因为类型是有效密封的,所以您可以放心,只有两种情况,并且最终每个操作都必须根据either方法进行定义,这将迫使调用者处理这两种情况。

关于您试图解决的问题class Left<L> extends Either<L,?>,请考虑签名<A, B> Either<A, B> left(A value)。类型参数B未出现在参数列表中。因此,考虑到某种类型的值A,你可以得到一个Either<A, B>任何 类型B



 类似资料:
  • 我试图建立一个具有联合数据类型支持成员记录类型的AVRO复杂记录。 我在尝试读取这种模式时出错。 我想知道-是否有可能声明这样的AVRO模式-其中一个字段类型是复杂用户定义消息结构的联合。 如果可能的话,你能让我知道我做错了什么吗?或者用union类型字段的类型定义举例说明这种结构吗? 我想使用AVRO的动态架构用法 - 因此请指定此架构文件运行时并将传入缓冲区解析为“request”/“resp

  • 使用合成标记和图层标记可存储注释和其他元数据,以及标记合成或图层中的重要时刻。合成标记显示在合成的时间标尺上,而每个图层标记显示在相应图层的持续时间条上。两种标记都可以保存相同的信息。 标记可以指单个时间点,也可以指一段持续时间。 After Effects 中的合成标记对应于 Adobe Premiere Pro 中的顺序标记。After Effects 中的图层标记对应于 Adobe Prem

  • Sphinx 使用文本解释角色在文档中插入语义标签. 这样写 :rolename:`content`. Note 默认角色 (`content`) 并不特别. 可使用任何其他有效的名字来代替; 使用 :confval:`default_role` 设置. 由主域添加的角色请参考 Sphinx Domains . 交叉索引的语法 多数文本解释角色都会产生交叉索引. 需要写一个 :role:`targ

  • 我已经找了一段时间了,但是找不到一个明确的答案。 很多人说使用联合来键入双关语是不明确的,也是不好的做法。这是为什么呢?我看不出它会做任何未定义的事情的任何理由,考虑到你写入原始信息的内存不会自动改变(除非它超出了堆栈的范围,但这不是一个联合问题,这将是一个糟糕的设计)。 人们引用严格的混淆现象规则,但在我看来,这就像说你做不到,因为你做不到。 此外,如果不打双关语,工会还有什么意义?我在某个地方

  • 主要内容:TypeScript,JavaScript,TypeScript,JavaScript,联合类型数组,TypeScript,JavaScript联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。 注意:只能赋值指定的类型,如果赋值其它类型就会报错。 创建联合类型的语法格式如下: 实例 声明一个联合类型: TypeScript var val:string|number val = 12 console.log("数字为 "+ val

  • 本节介绍联合类型,它使用管道符 | 把多个类型连起来,表示它可能是这些类型中的其中一个。我们把 | 理解成 or,这样便于轻松记忆。 1. 慕课解释 联合类型与交叉类型很有关联,但是使用上却完全不同。区别在于:联合类型表示取值为多种中的一种类型,而交叉类型每次都是多个类型的合并类型。 语法为:类型一 | 类型二。 2. 简单示例 联合类型之间使用竖线 “|” 分隔: let currentMont