2017-11-15 20 views
2

다음 매크로가 있습니다. StringContent은 열거 형 항목입니다. 내가 지금은 제가 해봤 그래서다음 from_str 매크로를 from_json으로 어떻게 변경합니까?

from_json!({ 
    "appName": "Demo App", 
    "appVersion": "1.0", 
    "database": { 
     "host": "dev.database.com", 
     "port": 3000 
    } 
}) 

처럼 r#""#을 제거 할 수 있습니다 다른 매크로 from_json!을 원하는

from_str!(r#"{ 
    "appName": "Demo App", 
    "appVersion": "1.0", 
    "database": { 
     "host": "dev.database.com", 
     "port": 3000 
    } 
}"#) 

과 같은 코드를 작성할 수 있습니다

#[macro_export] 
macro_rules! from_str { 
    ($json:expr) => {   
     StringContent(String::from($json)) 
    } 
} 

작동하지 않는 다음의 것

#[macro_export] 
macro_rules! from_json { 
    ($t:tt) => {   
     StringContent(String::from(concat!(r#"r#""#, stringify!($t), r#"""# , r#"#"#))) 
    } 
} 

from_json을 작동 시키려면 어떻게해야합니까?

+0

AFAIK, 연결을 사용할 수 없습니다! 'r'및 '#'문자로 시작하는 문자열을 생성하므로 원하는 방식으로 실제로는 이스케이프 처리하지 않습니다. 또한 포함 시키십시오! 실제 파일을 포함 할 것이고, 당신이 여기에서하고 싶은 것과는 분명 다릅니다. 왜 그 매크로를 사용 했습니까? 이스케이프 처리 된 텍스트가있는 파일을 만든 다음 다시 파싱 할 계획이 있습니까? –

+0

@JanNilsFerner 그 통찰력을 가져 주셔서 감사합니다. 나는 내 대답을 편집하여 include를 제거했습니다! 및 향상된 concat! 사용법 조금. 그래도 여전히 작동하지 않습니다. – Harindaka

+0

그것은 물건을 깨끗이합니다. 귀하의 접근 방식은 불행히도 여전히 작동하지 않습니다, 이유에 대한 자세한 내용은 내 대답을 참조하십시오. –

답변

3

나는 당신의 정확한 구문과 함께 작동하는 json macro provided by serde_json, 사용하십시오 :

#[macro_use] 
extern crate serde_json; 
extern crate serde; 

fn main() { 
    let x = json!({ 
     "appName": "Demo App", 
     "appVersion": "1.0", 
     "database": { 
      "host": "dev.database.com", 
      "port": 3000 
     } 
    }); 
} 

이것은 Value 구조체를 생성한다. 어떤 이유로 든 문자열로 다시 필요하면 다음과 같이 직렬화해야합니다.

extern crate serde; 
#[macro_use] 
extern crate serde_json; 

struct StringContent(String); 

macro_rules! from_json { 
    ($x:tt) => {{ 
     let tmp = json!($x); 
     let s = serde_json::to_string(&tmp).expect("Invalid JSON"); 
     StringContent(s) 
    }} 
} 

fn main() { 
    let x = from_json!({ 
      "appName": "Demo App", 
      "appVersion": "1.0", 
      "database": { 
       "host": "dev.database.com", 
       "port": 3000 
      } 
     }); 

    println!("{}", x.0) 
} 
+0

'serde_json' 만'serde' 자체를 포함 할 필요가 없습니다. 또한 OP는 'serde_json :: Value'가 아닌'& str'을 사용하려고합니다. 아마도 그는 그것을 다시 생각해야합니다. –

+0

@JanNilsFerner 'extern crate serde;'는 방어 프로그래밍 (serde_derive에 필요하기 때문에)이므로 다른 serde 크레이트를 사용하면 항상 포함됩니다. – Shepmaster

+0

충분히 합리적으로 들리 겠지만. –

4

concat!을 구문 적으로 건전한 방식으로 서로 식별자를 추가하는 데 사용할 수 없으므로 매크로가 작동하지 않습니다. 대신 식별자를 문자열로 연결합니다. 현재 및 #이 리터럴 문자 인 "r#\" ~your JSON~ \"#"처럼 보입니다.

a stabilized, extended concat_idents! is implemented까지 접근법이 작동하지 않습니다.

매크로에서 손으로 JSON 구문을 구문 분석해야합니다. 영감을 얻으려면 how Serde does it을 살펴보십시오.

serde_json 일반적으로 사용 사례에 매우 잘 맞는 것 같습니다. 가능한 경우 JSON 구문 분석의 사용자 지정 구현을 제거하고 대신 serde_json을 사용하는 것이 좋습니다. 이는 Rust의 모든 JSON에 대한 사실상의 표준 선택이므로

이 serde_json와 원시 문자열로 JSON 변환하는 방법에 대한 최소한의 예는 다음과 같습니다

#[macro_use] 
extern crate serde_json; 

fn main() { 
    let as_json_value = json!({ 
     "appName": "Demo App", 
     "appVersion": "1.0", 
     "database": { 
      "host": "dev.database.com", 
      "port": 3000 
     } 
    }); 
    let as_string = format!("{}", as_json_value); 
    println!("{}", as_string); 
} 

당신은 아마 이미 한, 당신의 StringContent 열거는 serde_json::Value에서 건설 될 재 작성하는 것이 좋습니다 있지만 깔끔하게 당신을 위해 파싱.