serde_json generic type deserialize

joonpark·2022년 1월 3일
0

42_cli

목록 보기
1/5

문제

아래 코드는 API 호출로 받아온 JSON data를 deserialize하는 함수다. 그런데 이 함수가 호출하는 API에 따라 반환하는 타입이 달라진다. 여기서 문제가 있는데 타입만 다른데 똑같은 모양의 함수를 만드는게 비효율적이라는 것. 그래서 generic type을 받도록 바꿔봤는데 잘 되지 않는다.

fn jsonize(text: &str) -> Result<Vec<Campus>, serde_json::Error> {
    let camp: Vec<Campus> = serde_json::from_str(text)?;
    Ok(camp)
}
// Campus 대신 Coalition이 올 수도 있다.
fn jsonize(text: &str) -> Result<Vec<Coalition>, serde_json::Error> {
  let camp: Vec<Coalition> = serde_json::from_str(text)?;
  Ok(camp)
}

아래는 generic type처럼 작동할 줄 알았던 코드

fn jsonize<T>(text: &str) -> Result<Vec<T>, serde_json::Error> {
    let camp: Vec<T> = serde_json::from_str(text)?;
    Ok(camp)
}

원인

찾아보니까 rust의 lifetime과 관련이 있어 보인다.
lifetime github
lifetime stackoverflow

lifetime 이전에 다른 문제가 있다.
generic type 함수를 만들었다. 함수는 generic type T에 대해서 deserialize를 하는데, 이 T에는 어떤 type이든 올 수 있는게 문제다. 현재 함수는 serde_json::from_str() 함수를 호출하는데 이 함수는 deserialize trait을 가진 것에 대해서만 작동한다. integer, String, float 등 ... 어떤 type이라도 올 수 있기 때문에 함수는 잘못됐고, trait bound로 특정 trait을 가진 type T에만 작동하도록 고쳐야된다.

fn jsonize<T: Deserialize>(text: &str) -> Result<Vec<T>, serde_json::Error> {
    let camp: Vec<T> = serde_json::from_str(text)?;
    Ok(camp)
}

코드를 좀 다듬으면

fn jsonize<T>(text: &str) -> Result<Vec<T>, serde_json::Error>
	where T: Deserialize
{
    let camp: Vec<T> = serde_json::from_str(text)?;
    Ok(camp)
}

이제 여기서부터 lifetime 문제다.

serde_json::from_str() 함수 선언은 아래와 같다.

serde_json::de
pub fn from_str<'a, T>(s: &'a str) -> Result<T>
where
    T: de::Deserialize<'a>,

from_str() 함수는 lifetime을 가지고 있다. 그런데 내가 작성한 jsonize() 함수는 lifetime이 명시되지 않았다. 그래서 from_str() 함수에서 필요한 lifetime보다 작은지 borrow checker로 확인할 때 걸릴 수 있다. 'a로 lifetime을 명시해 해결할 수 있다.

어ㅓ어어 뭔가 부조가한데

0개의 댓글