【问题标题】:Map pattern matching in function head函数头中的映射模式匹配
【发布时间】:2021-06-22 06:11:31
【问题描述】:

我正在尝试创建一个接受两个参数的函数,一个由三个元素组成的元组,以及一个将分配元组值中最后两个元素的映射。所以例如我会这样调用函数

modulename:funcName({description, a,b}, #{a=>1, b=>2)).

我无法让模式匹配工作。我的功能是这样的

funcName({description,a,b}, #{a:=A, b:=2}.

我无法将元组中的原子映射到映射中的值。我该怎么办。

【问题讨论】:

    标签: erlang pattern-matching


    【解决方案1】:

    如果我正确理解了您想要的内容,则无法在函数头本身中执行此操作,因为用作映射键的所有变量都必须事先绑定。来自the OTP 23 highlights blog post

    下面有一个非法示例,表明仍然不支持使用未绑​​定变量作为键模式表达式的一部分。在这种情况下,Key 没有被绑定,并且要求键表达式中使用的所有变量都必须事先绑定。

    illegal_example(Key, #{Key := Value}) -> Value.
    

    所以你必须这样写:

    func_name({description, Key1, Key2}, Map = #{}) ->
        #{Key1 := Value1, Key2 := Value2} = Map,
        ....
    

    之所以可行,是因为在第二行,变量 Key1Key2 已经绑定,因此它们可以用来匹配映射中相应键的值。

    或者,使用maps:get 来实现相同的结果:

    func_name({description, Key1, Key2}, Map = #{}) ->
        Value1 = maps:get(Key1, Map),
        Value2 = maps:get(Key2, Map),
        ....
    

    【讨论】:

    • 这个 Map#{} 不是需要一张空地图吗?我不明白我会从哪里得到 Value1 和 Value2,因为它是一张空地图
    • 不,在模式匹配中#{} 代表任何地图,无论是否为空。添加when is_map(Map)也可以达到同样的效果。如果第二个参数不是地图,这只是为了得到一个描述性错误,尽管你可以说你在下一行得到的错误匹配错误同样清楚。
    • 好的,但是我还是不明白 Value1 和 Value2 是从哪里来的。我应该使用 maps:get/2 来获取值吗?
    • Value1Value2 通过模式匹配绑定到映射中相应键的值。您也可以使用maps:get - 我添加了一个示例。
    • 好的,我将代码更改为ibb.co/dKvq99f,但我仍然收到此警告和错误ibb.co/dKvq99fhttps://ibb.co/R9TC53P。我仍然无法用我的代码将原子映射到值
    【解决方案2】:

    您可以分两步完成(将模式匹配保持在函数头级别):

    funcName(T = {description,A,B}, Map) ->
        funcName(T, maps:get(Map,A,undefined), maps:get(Map,B,undefined), Map).
    
    funcName({description,a,b}, A, 2, Map) when A =/= undefined ->
        ...
    

    编辑

    我刚刚重新阅读了您的问题,现在不明白什么不起作用。它可以一步完成,用你的代码(和一个小的语法更正):

    -module (test).
    
    -export ([funcName/2]).
    
    funcName({description,a,b}, #{a := A, b := 2}) ->
        A;
    funcName(_,_) ->
        error.
    

    你可以测试一下:

    1> test:funcName({description,a,b},#{a => "hello", b => 2}).
    "hello"
    2> test:funcName({description,a,b},#{a => "hello", b => 3}).
    error
    3> test:funcName({description,a,b},#{a => "hello", c => 2}).
    error
    4> test:funcName({description,a,b},#{aa => "hello", b => 2}).
    error
    5> test:funcName({description,a,bb},#{a => "hello", b => 2}).
    error
    6> test:funcName({description,a,b,c},#{a => "hello", b => 2}).
    error
    7>
    

    【讨论】:

    • 也许我应该更清楚。函数的输入应该可以是 modulename:funcname({description,a,b},#{a=>2,b=3})。所以我不明白这个 funcName({description,a,b}, #{a := A, b := 2}) -> A;可以是解决方案。值映射原子 b 不应该在函数头中确定,而是由输入确定
    猜你喜欢
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多