【问题标题】:Erlang illegal pattern while working with list of records使用记录列表时的 Erlang 非法模式
【发布时间】:2016-03-10 12:09:46
【问题描述】:

我正在尝试用 Erlang 编写简单的通讯录。我已经开始了:

-record(entry, {name, surname, phone, email}).

createAdressBook() -> [].

addContact(Name, Surname, AdressBook) ->
  case isAlready(Name, Surname, AdressBook) of
    false -> [#entry{name = Name, surname = Surname}|AdressBook];
    _ -> {error, "This entry already exists"}
  end.

isAlready(_, _, []) -> false;
isAlready(Name, Surname, [#entry{name = Name, surname = Surname}|_]) -> true;
isAlready(Name, Surname, [_|T]) -> isAlready(Name, Surname, T).

但是,过了一段时间,我决定把名字和姓氏放在一起。将代码更改为以下代码后会引发编译错误(new isAlready/3 第二行中的非法模式。

-record(entry, {person, phone, email}).

createAdressBook() -> [].

addContact(Name, Surname, AdressBook) ->
  case isAlready(Name, Surname, AdressBook) of
    false -> [#entry{person = Name ++ " " ++ Surname}|AdressBook];
    _ -> {error, "This entry already exists"}
  end.

isAlready(_, _, []) -> false;
isAlready(Name, Surname, [#entry{person = Name ++ " " ++ Surname}|_]) -> true;
isAlready(Name, Surname, [_|T]) -> isAlready(Name, Surname, T).

我做错了什么以及为什么要检查 string1 + " " + string2 是否是列表的头部?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    您正在尝试在函数头中执行操作,而不仅仅是在使用 ++ 时进行匹配。所以这行不通。相反,利用调用函数中的机会只创建一次您的 Person 值,并从那里始终如一地使用它:

    -record(entry, {person, phone, email}).
    
    createAdressBook() -> [].
    
    add_contact(Name, Surname, AdressBook) ->
      Person = Name ++ " " ++ Surname,
      case is_already(Person, AdressBook) of
        false -> [#entry{person = Person}|AdressBook];
        _ -> {error, "This entry already exists"}
      end.
    
    is_already(_, []) -> false;
    is_already(Person, [#entry{person = Person}|_]) -> true;
    is_already(Person, [_|T]) -> is_already(Person, T).
    

    或者,您可以使用记录和元组索引的属性来使用搜索功能,而不是自己编写:

    is_already(Person, AddressBook) ->
        case lists:keyfind(Person, #entry.person, AddressBook) of
            #entry{} -> true;
            false    -> false
        end.
    

    作为风格说明——您注意到我将函数名称从isAlready 更改为is_already。在 Erlang 中,大写单词有特殊含义,为了防止混淆,我们简单地将 all_lower_and_underscores 用于函数名,将 AllUpperCamelCase 用于变量。

    【讨论】:

    • 我决定使用我的解决方案,因为它避免使用连接,但我将您的解决方案标记为已接受,因为您解决了为什么 ++ 在模式匹配中不起作用的问题。谢谢你:)
    【解决方案2】:

    就在 zxq9 发布他的答案之前,我发现另一种解决方案是将 name 和 surname 作为记录的 person 字段中的元组。

    -record(entry, {person, phone, email}).
    
    createAdressBook() -> [].
    
    addContact(Name, Surname, AdressBook) ->
      case isAlready(Name, Surname, AdressBook) of
        false -> [#entry{person = {Name, Surname}}|AdressBook];
        _ -> {error, "This entry already exists"}
      end.
    
    isAlready(_, _, []) -> false;
    isAlready(Name, Surname, [#entry{person = {Name, Surname}}|_]) -> true;
    isAlready(Name, Surname, [_|T]) -> isAlready(Name, Surname, T).
    

    【讨论】:

    • 确实!无论如何,这可能是一个更好的全方位解决方案,因为您避免在内部处理数据。当然,在这种情况下,它是架构的一个点,而不是匹配技术,但我希望将它们实际连接成一个字符串的唯一地方是当您向用户或另一个期望格式化数据的系统呈现输出时。跨度>
    【解决方案3】:

    当使用 ++ 进行模式匹配时,编译时必须知道标题元素。 例如,

    TitledName = "Mr. Black",
    "Mr. "++LastName= TitledName
    

    就像:

    [$M, $r, $., $\s|LastName]= TitledName.
    

    【讨论】:

      猜你喜欢
      • 2011-11-10
      • 1970-01-01
      • 2011-06-24
      • 2023-03-28
      • 2014-05-31
      • 2013-06-25
      • 2018-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多