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

Update element on map depending on other update

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

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"

如果我 updateInfo() 并且年龄是 17 岁,我希望此人将观察结果更改为 "Adult"。但它不起作用。我以为地图的更新是按顺序进行的,但显然不是,所以我不能相信现在的年龄是 18 岁这一事实。如果我像这样拆分更新,我可以做到这一点:

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

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

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

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))

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

有很多方法可以完成单机任务:

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)

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