#TIL #elixirlang 구조체(struct)를 jason을 사용해 인코딩하려면
csv로 저장하려고 했는데, jason 라이브러리를 사용하면 직렬화(serialization), 역직렬화(deserialization)가 편해서 json 포멧을 사용한다.
defmodule Data do
defstruct [:a, :b, :c, :d]
end
Data
구조체를 만들고 이걸 json으로 인코딩해본다.
content = %Data{a: 1, b: 2, c: 3, d: 4}
Jason.encode!(content, pretty: true)
** (Protocol.UndefinedError) protocol Jason.Encoder not implemented for %Data{a: 1, b: 2, c: 3, d: 4} of type Data (a struct), Jason.Encoder protocol must always be explicitly implemented.
If you own the struct, you can derive the implementation specifying which fields should be encoded to JSON:
@derive {Jason.Encoder, only: [....]}
defstruct ...
It is also possible to encode all fields, although this should be used carefully to avoid accidentally leaking private information when new fields are added:
@derive Jason.Encoder
defstruct ...
Finally, if you don't own the struct you want to encode to JSON, you may use Protocol.derive/3 placed outside of any module:
Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
Protocol.derive(Jason.Encoder, NameOfTheStruct)
. This protocol is implemented for the following type(s): Any, Atom, BitString, Date, DateTime, Decimal, Float, Integer, Jason.Fragment, List, Map, NaiveDateTime, Time
(jason) lib/jason.ex:150: Jason.encode!/2
Data
구조체에 대한 Jason.Encoder
프로토콜이 구현 안 됐다며 에러가 난다. 도움말이 너무 친절해 그대로 따라 하면 된다.
defimpl Jason.Encoder, for: Data do
def encode(value, opts) do
Jason.Encode.map(Map.take(value, [:a, :b, :c, :d]), opts)
end
end
이렇게 직접 구현하던가
defmodule Data do
@derive Jason.Encoder
defstruct [:a, :b, :c, :d]
end
@derived
속성을 사용해 기본 구현을 사용한다고 알려주면 된다.
iex> Jason.encode!(content, pretty: true)
"{\n \"a\": 1,\n \"b\": 2,\n \"c\": 3,\n \"d\": 4\n}"
구조체도 json으로 인코딩이 잘 된다.
@derived
속성을 사용하면 __deriving__
콜백 함수가 호출된다. :only, :except 옵션을 사용하지 않으면 struct 키만 빼고 인코딩한다. 프로토콜을 구현할 때, __deriving__
콜백을 구현해놓으면 사용하는 사람이 편하다.
encode.ex 파일 구현을 보면 Date, Time, NaiveDateTime, DateTime 구조체는 미리 정의해놨다. 사용자가 의도하지 않는 인코딩을 방지하려고 구조체를 인코딩하려고 하면 에러를 일으킨다. 의도한 게 맞다면 구현하기 쉽게 @derived
속성을 사용하게 구현을 해놨다. 의도하지 않은 사용은 방지하고 원한다면 쉽게 구현할 수 있게 디자인했다. 정석처럼 잘해놨다.