Что такое «стандартный» способ объединения строк?

Хотя я в основном понимаю, что str и std::string::String и как они связаны друг с другом, я нахожу немного громоздким составлять строки из разных частей, не тратя слишком много времени и обдумывая это. Так что, как обычно, я подозреваю, что пока не нашел правильного способа сделать это, что делает его интуитивно понятным и легким.

let mut s = std::string::String::with_capacity(200);
let precTimeToJSON = | pt : prectime::PrecTime, isLast : bool | {
    s.push_str(
        "{ \"sec\": " 
       + &(pt.sec.to_string()) 
       + " \"usec\": " 
       + &(pt.usec.to_string()) 
       + if isLast {"}"} else {"},"})
    };    

Приведенный выше код учитывается компилятором с такими сообщениями об ошибках, как:

  

src \ main.rs: 25: 20: 25:33 ошибка: двоичная операция + не может быть применена к типу &'static str [E0369]

И даже после того, как я потратил полчаса на то, чтобы возиться и случайно добавить &, я не смог сделать его компилируемым. Итак, вот мои вопросы:

  • Что мне нужно написать, чтобы достичь очевидного?
  • Что такое "стандартный" способ сделать это в Rust?
12 голосов | спросил BitTickler 10 J000000Friday15 2015, 05:02:59

3 ответа


0

Компилятор Rust прав (конечно): для строковых литералов нет оператора +.

Я считаю, что format!() macro - идиоматический способ сделать то, что вы пытаетесь сделать. Он использует std::fmt синтаксис , который по существу состоит из строки форматирования и аргументов для форматирования ( а-ля C printf). Для вашего примера это будет выглядеть примерно так:

let mut s: String = String::new();
let precTimeToJSON = | pt : prectime::PrecTime, isLast : bool | {
    s = format!("{{ \"sec\": {} \"usec\": {} }}{}",
        pt.sec,
        pt.usec,
        if isLast { "" } else { "," }
    )
};

Поскольку это макрос, вы можете свободно смешивать типы в списке аргументов, если этот тип реализует std::fmt::Display trait (это верно для всех встроенных типов). Кроме того, вы должны экранировать литерал { и } как {{ и ---- +: = 9 =: + ---- соответственно. Наконец, обратите внимание, что строка формата должна быть строковым литералом, потому что макрос анализирует его, а расширенный код не выглядит как оригинальное выражение }} .

Вот ссылка на игровую площадку на приведенный выше пример.

Еще два момента для вас. Во-первых, если вы читаете и пишете JSON, взгляните на такую ​​библиотеку, как rustc-serialize . Это гораздо менее болезненно!

Во-вторых, если вы просто хотите объединить строки format! (то есть строковые литералы), вы можете сделать это с нулевым затраты времени с помощью &'static str макрос . Это не поможет вам в вашем случае выше, но может быть с другими подобными.

ответил George Hilliard 10 J000000Friday15 2015, 05:45:45
0

Itertools::format может помочь вам написать это как одно выражение, если вы действительно хотите.

let times: Vec<PrecTime>; // iterable of PrecTime
let s = format!("{}", times.iter().format(",", |pt, f|
    f(&format_args!(r#"{{ "sec": {}, "usec": {} }}"#, pt.sec, pt.usec))
));

format() использует разделитель, поэтому просто укажите "," там (или "", если вам не нужен разделитель). Это немного связано с тем, что форматирование может быть полностью ленивым и составным. Вы получаете обратный вызов f, который вы перезваниваете с &Display (все, что может быть отформатировано для отображения).

Здесь мы продемонстрируем этот замечательный прием использования &format_args!() для создания отображаемого значения. Это очень удобно, если вы используете API построителя отладки .

Наконец, используйте необработанную строку, чтобы нам не нужно было экранировать внутренний " в формате: r#"{{ "sec": {} "usec": {} }}"#. Необработанные строки разделяются r#" и "# (свободный выбор номера #).

Itertools::format() не использует промежуточных выделений, все это напрямую передается базовому объекту форматирования.

ответил bluss 11 J000000Saturday15 2015, 12:59:14
0

Вы также можете сделать это безумие:

fn main() {
    let mut s = std::string::String::with_capacity(200);

    // Have to put this in a block so precTimeToJSON is dropped, see https://doc.rust-lang.org/book/closures.html
    {
        // I have no idea why this has to be mut...
        let mut precTimeToJSON = |sec: u64, usec: u64, isLast: bool| {
            s.push_str(&( // Coerce String to str. See https://doc.rust-lang.org/book/deref-coercions.html
                "{ \"sec\": ".to_string()      // String 
                + &sec.to_string()             // + &str    (& coerces a String to a &str).
                + " \"usec\": "                // + &str
                + &usec.to_string()            // + &str
                + if isLast {"}"} else {"},"}  // + &str
            ));
        };
        precTimeToJSON(30, 20, false);
    }
    println!("{}", &s);
}

Обычно оператор String + &str -> String определен, так что вы можете сделать String + &str + &str + &str + &str. Это дает вам String, который вы должны вернуть к &str используя &. Я думаю, что этот способ, вероятно, довольно неэффективен, поскольку он (возможно) будет распределять нагрузки по String s.

ответил Timmmm 10 J000000Friday15 2015, 13:51:36

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132