根据其他更新在地图上更新元素

时间:2017-09-30 20:23:25

标签: dictionary elixir updates

我想更新地图,执行以下操作:

def updateInfo() do
  person = %{ person | name : "new name", age : person.age +1, observation : changeObs(person.age)}
end

def changeObs(age), when age >= 18, do: "Adult"
def changeObs(age), do: "kid"

如果我更新了信息()并且年龄为17岁,我希望此人将观察结果更改为“成人”。但它没有用。我认为地图的更新是按顺序完成的,但显然不是,所以我不能依赖现在年龄为18的事实。如果我像这样拆分更新,我可以这样做:

person = %{ person | name : "new name", age : person.age +1}
person = %{ person | observation : changeObs(person.age)}

有没有办法将所有更新保留在一行中,依赖于以前地图上属性的更新?

2 个答案:

答案 0 :(得分:2)

好吧,据我所知,您可以将新值缓存在变量中:

new_age = person.age + 1
person = %{ person | name: "new name", age: new_age, observation: changeObs(new_age)}

或者你可以这样改变:

person
|> Map.put(:name, "new_name")
|> Map.put(:age, new_age)
|> Map.put(:observation, changeObs(new_age))

答案 1 :(得分:1)

首先,更新地图的语法使用冒号,而不是等号。您的代码会引发SyntaxError异常。

有很多方法可以像oneliner一样完成任务:

person = with age <- person.age + 1,
          do: %{person | age: age, 
                         observation: (if age >= 18, do: "Adult", else: "Kid")}

或者:

person = (age = person.age + 1;
          %{person | age: age, 
                     observation: (if age >= 18, do: "Adult", else: "Kid")})

或管道链:

{_, person} = person
              |> Map.put(:age, person.age + 1)
              |> Map.get_and_update(:age, fn age ->
                   {age, age + 1}
                 end)

惯用语将是最后一个。我最喜欢的是第一个。