My use case is I want to dynamically match a struct based on the struct type, and a key in the struct.
Example:
defmodule Thing do
defstruct [:id, :name]
end
things = [
%Thing{id: 1, name: "thing1"},
%Thing{id: 2, name: "thing2"},
# ..other stuff, could be non-Thing structs..
]
type = Thing
id = 2
match = %{__struct__: type, id: id}
Enum.find(things, fn thing -> match?(^match, thing) end)
# => nil
match?/2 returns false here:
iex(1)> match
%{__struct__: Thing, id: 2}
iex(2)> match?(^match, %Thing{id: 2, name: "thing2"})
false
iex(3)> %{__struct__: Thing, id: 2} = %Thing{id: 2, name: "thing2"}
%Thing{id: 2, name: "thing2"}
Or with a case statement:
case %Thing{id: 2, name: "thing2"} do
%{__struct__: Thing, id: 2} -> :ok
_ -> :not_ok
end
=> :ok
Now if we assign the pattern to a variable with match = %{__struct__: Thing, id: 2}
, it no longer works.
case %Thing{id: 2, name: "thing2"} do
^match -> :ok
_ -> :not_ok
end
=> :not_ok
I’m curious 1. why does behave this way? 2. What is the right way to achieve what I’m trying to achieve. Assuming that the list could be mixed structs.