2017-06-22 53 views
5

Moim początkowym zamiarem było przekonwertowanie podpisanej liczby pierwotnej na jej reprezentację szesnastkową w sposób, który zachowuje znak liczby. Okazuje się, że obecne implementacje LowerHex, UpperHex i krewnych dla podpisanych liczb całkowitych po prostu traktują je jako niepodpisane. Niezależnie od tego, jakie dodatkowe flagi formatowania dodaję, te implementacje wydają się po prostu ponownie interpretować liczbę jako niepodpisany odpowiednik dla celów formatowania. (Playground)Jak sformatować liczbę całkowitą ze znakiem w reprezentującą szesnastkową reprezentację znaku?

println!("{:X}", 15i32);   // F 
println!("{:X}", -15i32);   // FFFFFFF1 (expected "-F") 
println!("{:X}", -0x80000000i32); // 80000000 (expected "-80000000") 
println!("{:+X}", -0x80000000i32); // +80000000 
println!("{:+o}", -0x8000i16);  // +100000 
println!("{:+b}", -0x8000i16);  // +1000000000000000 

Dokumentacja w std::fmt nie jest jasne, czy to ma się wydarzyć, czy jest jeszcze ważna, a UpperHex (lub jakakolwiek inna cecha formatowanie), nie wspominając, że implementacje dla podpisanych liczb interpretować liczby jako unsigned. Wygląda na to, że nie ma żadnych powiązanych problemów w repozytorium Rust GitHub.

Ostatecznie można zaimplementować określone funkcje dla zadania (jak poniżej), z niefortunną wadą braku dużej kompatybilności z API formatyzatora.

fn to_signed_hex(n: i32) -> String { 
    if n < 0 { 
     format!("-{:X}", -n) 
    } else { 
     format!("{:X}", n) 
    } 
} 

assert_eq!(to_signed_hex(-15i32), "-F".to_string()); 

Czy to zachowanie dla zamierzonych liczb całkowitych ze znakiem? Czy istnieje sposób, aby wykonać tę procedurę formatowania, zachowując jednocześnie standard Formatter?

Odpowiedz

4

Czy istnieje sposób wykonania tej procedury formatowania przy zachowaniu standardu Formatter?

Tak, ale należy wprowadzić nowy typ, aby zapewnić wyraźną implementację UpperHex. Oto implementacja że szanuje +, # i 0 flagi (i ewentualnie więcej, nie testowałem):

use std::fmt::{self, Formatter, UpperHex}; 

struct ReallySigned(i32); 

impl UpperHex for ReallySigned { 
    fn fmt(&self, f: &mut Formatter) -> fmt::Result { 
     let prefix = if f.alternate() { "0x" } else { "" }; 
     let bare_hex = format!("{:X}", self.0.abs()); 
     f.pad_integral(self.0 >= 0, prefix, &bare_hex) 
    } 
} 

fn main() { 
    for &v in &[15, -15] { 
     for &v in &[&v as &UpperHex, &ReallySigned(v) as &UpperHex] { 
      println!("Value: {:X}", v); 
      println!("Value: {:08X}", v); 
      println!("Value: {:+08X}", v); 
      println!("Value: {:#08X}", v); 
      println!("Value: {:+#08X}", v); 
      println!(); 
     } 
    } 
} 
+0

Przysięgam dostęp do opcji formater nie stosowanych tam być, ale wygląda na to, byłem tam od 1.5.0, więc nie wiem, o czym myślałem. – Shepmaster

+0

Cóż ['flags()'] (https://doc.rust-lang.org/nightly/std/fmt/struct.Formatter.html#method.flags) było zawsze tam, po prostu "to, co jest tym, co "nie jest tak naprawdę udokumentowane ... –