
Size: a a a















1.48 (19 ноября 2020, через полторы недели).

u32? Наш код вполне может работать с другими типами! Давайте это исправим:macro_rules! make_literal {
    (($n:expr) : $ty:ty) => {{
        // то же, что и было, но заменяем u32 на $ty
        STR: &str = ...;
        STR
    }}
}const STR: &str = make_literal!((41 + 1): u32);
fn main() {
assert_eq!(STR, "42");
}
const STR: &str = make_literal!((-41 - 1): i32);
fn main() {
assert_eq!(STR, "-42");
}
error: any use of this value will cause an error
--> src/main.rs:42:26
|
42 | ret[i] = (n % 10) as u8 + b'0';
| ^^^^^^^^^^^^^^^^^^^^^
| |
| attempt to compute `254_u8 + 48_u8`, which would overflow
| inside `to_ascii` at src/main.rs:42:26
| inside `DECOMPOSED` at src/main.rs:59:48
const fn extract_digit(n: $ty) -> $ty {
    let mut ret = n % 10;
    #[allow(unused_comparisons)]
    // ^ сравнение не имеет смысла для беззнаковых чисел
    if ret < 0 {
        // мы не можем написать ret = -ret,
        // поскольку унарный минус не определён для беззнаковых
        ret = 0-ret;
    }
    ret
}const fn digits_len(mut n: $ty) -> usize {
    if n == 0 {
        return 1;
    }
    let mut n_digits = 0;
    #[allow(unused_comparisons)]
    if n < 0 {
        n_digits += 1;
    }
    ...
}
...
const fn to_ascii(mut n: $ty) -> ([u8; LEN], usize) {
    #[allow(unused_comparisons)]
    let is_negative = n < 0;
    ...
    while n != 0 {
        ret[i] = extract_digit(n) as u8 + b'0';
        n /= 10;
        i += 1;
    }
    if is_negative {
        ret[i] = b'-';
        i += 1;
    }
    ...const STR: &str = make_literal!((-41 - 1): i32);
fn main() {
assert_eq!(STR, "-42");
}
macro_rules! после expr нельзя ставить двоеточие, из-за чего мне пришлось внести в синтаксис раздражающие скобки. Как известно, всякую проблему можно решить ещё одним слоем абстракции, поэтому я именно этим и воспользуюсь: я сделаю макрос, который принимает имя и тип и генерирует ещё один макрос с переданным именем, который принимает выражение нужного типа и уже возвращает константу:macro_rules! make_literal_maker {
    ($name:ident : $ty:ty) => {
        macro_rules! $name {
            ($n:expr) => {{
                // весь остальной код без изменений
            }}
        }
    }
}make_literal_maker!(make_str_literal_from_usize: usize);
make_literal_maker!(make_str_literal_from_i8: i8);
const STR_UNSIGNED: &str = make_str_literal_from_usize!(41 + 3 - 2);
const STR_SIGNED: &str = make_str_literal_from_i8!(-100 - 1);
fn main() {
assert_eq!(STR_UNSIGNED, "42");
assert_eq!(STR_SIGNED, "-101");
}

