6

我正在使用 Javaslang-2.1.0-alpha 及其 Javaslang-match 等效项来进行一些对象分解。根据Daniel 在“Match the Fancy way”部分的博客文章:

Match(person).of( Case(Person("Carl", Address($(), $())), (street, number) -> ...) )

Address应该检索与内部两个通配符模式匹配的值streetnumber但该示例甚至无法编译。后来我意识到所有对象都必须包装在原子模式中,即“Carl”变为$(“Carl”)。这是在阅读了这个问题之后。

我按照更新的教程进行操作,但此示例没有更新。

我将示例更新为:

Person person = new Person("Carl", new Address("Milkyway", 42));

 String result2 = Match(person).of(
 Case(Person($("Carl"), Address($(),$())),
         (street, number) -> "Carl lives in " + street + " " + number),
 Case($(), () -> "not found")
 );
 System.out.println(result2);

它可以编译,但从控制台输出来看,我的值没有正确匹配:

Carl lives in Carl Address [street=Milkyway, number=42]

很明显,street包含Carlnumber,整个Address对象。

当我尝试添加第三个 lambda 参数来捕获Carl时:

 Case(Person($("Carl"), Address($(),$())),
         (name, street, number) -> "Carl lives in " + street + " " + number)

代码无法编译,lambda 表达式带有红色下划线,并带有以下错误文本:

The target type of this expression must be a functional interface

$_在最新版本的 javaslang-match 中,无法忽略一个值。所以我想匹配每个返回三个 lambda 参数的原子模式,如上所述。

我需要了解这个库的人向我解释如何在最新版本中进行对象分解。

4

1 回答 1

8

免责声明:我是 Javaslang 的创建者。

案例需要处理(字符串,地址)-> {...}。$() 匹配任意值,但处理程序/函数仅接收分解对象树的第一层。$() 在第二层。

规则:所有层都与模式匹配,只有第一层被传递给处理程序。

Match 的第一个原型实际上处理了任意树的深度,但方法必须在引擎盖下为所有可能的组合生成 - 最大字节码大小很容易超过并且编译时间以指数方式爆炸到无限。

当前版本的 Match 是我目前看到的 Java 中唯一实用的方法。

更新:

请让我就这个主题提供更具形象性的更新。

我们区分

  1. 输入的对象图
  2. 传递给匹配案例的模式树
  3. 对象图的分解对象

广告 1) 对象图

给定一个对象,通过遍历该对象的属性(分别是实例变量)来生成对象图。值得注意的是,我们不禁止对象包含循环(例如,包含自身的可变列表)。

在 Javaslang 中,没有自然的方法可以将对象分解成各个部分。为此,我们需要一个所谓的模式。

对象图示例:

     Person        <-- root
      /   \
 "Carl"  Address   <-- 1st level
          /   \
 "Milkyway"    42  <-- 2nd level

广告 2) 模式树

模式(实例)固有地定义了如何分解对象。

在我们的示例中,模式类型如下所示(简化的泛型):

 Pattern2<Person, String, Address<String, Integer>>
               /           \
 Pattern0<String>  Pattern2<Address, String, Integer>
                          /   \
          Pattern0<String>     Pattern0<Integer>

调用的模式方法返回上述类型的实例:

      Person(...)
        /    \
 $("Carl")  Address(...)
             /   \
           $()    $()

Javaslang 的 Match API 执行以下操作:

  1. Match 实例将给定person对象传递给第一个 Case。
  2. Case 将person对象传递给模式Person(...)
  3. Person(...)模式检查给定对象person是否为 类型Person
    • 如果为真,则模式将对象分解为其部分(由元组表示)并检查子模式是否$("Carl")匹配Address(...)这些部分(递归重复 3.)
    • 如果为 false,则 Match 将对象传递给下一个 Case(参见 2。)
    • 如果模式是原子的,即它不能再分解对象,则检查相等性并通知调用者一直回到匹配情况。
  4. 当匹配案例获得模式匹配时,它将对象图第一级的分解对象传递给匹配案例处理程序。

目前 Java 的类型系统不允许我们以类型化的方式将任意对象图/树级别的匹配对象传递给处理程序。

广告 3) 分解的对象

我们已经在上面 2) 中提到了对象分解。特别是当我们给定对象的一部分被向下发送到模式树时使用它。

由于我们上面提到的类型系统的限制,我们将匹配对象的过程与处理分解部分的过程分开。

Java 允许我们匹配任意对象图。我们不限于这里的任何级别。

但是,当一个对象匹配成功时,我们只能将第一层的分解对象传递给handler。

在我们的示例中,这些分解的对象是给定的(name而不是和)。addresspersonstreetnumber


我知道这对 Match API 的用户来说并不明显。

下一个 Java 版本将包含值对象和本机模式匹配!但是,该版本的模式匹配将完全限于第一级。

Javaslang 允许匹配任意对象图——但它是有代价的。处理程序确实只接收第一层分解对象,这可能会造成混淆。

我希望这以一种可以理解的方式回答了这个问题。

- 丹尼尔

于 2017-01-11T11:53:32.730 回答