Javaslang对象分解不起作用

时间:2017-01-11 10:52:56

标签: java lambda java-8 vavr

我正在使用Javaslang-2.1.0-alpha及其Javaslang-match相当于进行一些对象分解。根据丹尼尔在“匹配奇特的方式”部分中发表的this by blog帖子:

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

应检索与Address内的两个通配符模式匹配的值到streetnumber,但该示例甚至不编译。我后来意识到所有物体必须被包裹在原子模式中,即“Carl”变成$(“Carl”)。这是在阅读this issue之后。

我关注updated tutorial,但此示例没有更新。

我将示例更新为:

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包含 Carl number,整个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参数的原子模式,如上所述。

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

1 个答案:

答案 0 :(得分:8)

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

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

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

Match的第一个原型实际上处理了任意树深度,但是所有可能的组合都会在引擎盖下生成方法 - 容易超出最大字节代码大小并且编译时间呈指数级扩展为无限。

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

<强>更新

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

我们区分

  1. 输入的对象图
  2. 模式树已传递到匹配大小写
  3. 对象图的已分解对象
  4. 广告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. 案例将person对象传递给模式Person(...)
    3. Person(...)模式检查给定对象person是否为Person类型。
      • 如果为true,则模式将对象分解为其部分 (由元组表示)并检查子模式$("Carl")Address(...)是否与这些部分匹配(递归重复3)。
      • 如果为false,则Match将对象传递给下一个Case(参见2.)
      • 如果模式是原子的,即它不能再分解对象,则检查相等性,并通知呼叫者一直回到匹配情况。
    4. 当一个匹配案例得到一个模式匹配然后它将对象图的第一级的分解对象传递给匹配案例处理程序。
    5. 目前,Java的类型系统不允许我们以类型化的方式将任意对象图/树级的匹配对象传递给处理程序。

      广告3)分解的对象

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

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

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

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

      在我们的示例中,这些已分解的对象是给定name的{​​{1}}和address(而不是personstreet)。

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

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

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

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

      - 丹尼尔