Struct to struct mapping

Hi All.

is there a simple way to take an existing struct and map certain field values into a different second struct? My use case is I’d like to write a “log” file based on some key fields from a Plug Conn. I could just copy over the relevant fields or convert to a map and then to the second struct but I’m not sure if there is a better way.

cheers

Dave

That sounds fine, probably a single line anyway, could even look down into the ‘conn’ to pull out specific sub-values to put in your new struct by using get_in. :slight_smile:

Thanks @OvermindDL1 - is there any real performance overhead from converting and copying?

cheers

Dave

As long as you don’t ‘change’ the data as you copy it, nope, everything is immutable so quite literally they just point to the same bit of memory. :slight_smile:

What do you think about this:

defmodule Mapper do
  def map(struct1, struct2) do
    struct struct2, Map.from_struct(struct1)
  end
end

Here are some tests:

iex(1)> defmodule Struct1 do
...(1)>   defstruct one: 1, two: 2, three: 3, four: 4
...(1)> end
{:module, Struct1,
 <<70, 79, 82, 49, 0, 0, 9, 80, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 186,
   131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115,
   95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>,
 %Struct1{four: 4, one: 1, three: 3, two: 2}}
iex(2)> defmodule Struct2 do
...(2)>   defstruct one: 2, two: 2, five: 5
...(2)> end
{:module, Struct2,
 <<70, 79, 82, 49, 0, 0, 9, 64, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 186,
   131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115,
   95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>,
 %Struct2{five: 5, one: 2, two: 2}}
iex(3)> defmodule Mapper do
...(3)>   def map(struct1, struct2) do
...(3)>     struct struct2, Map.from_struct(struct1)
...(3)>   end
...(3)> end
{:module, Mapper,
 <<70, 79, 82, 49, 0, 0, 5, 80, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 169,
   131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115,
   95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>, {:map, 2}}
iex(4)> Mapper.map(%Struct2{}, %Struct1{})
%Struct1{four: 4, one: 2, three: 3, two: 2}
iex(5)> Mapper.map(%Struct1{}, %Struct2{})
%Struct2{five: 5, one: 1, two: 2}
iex(6)> Mapper.map(%Struct1{one: 42, two: 99}, %Struct2{})
%Struct2{five: 5, one: 42, two: 99}
iex(7)>

thanks @smpallen99 - in the end I simply copied the relevant fields but I’ll put your option in my toolset for later.

cheers

Dave

1 Like