如何将有符号整数格式化为符号可识别的十六进制表示?

E_n*_*ate 5 formatting integer rust

我的初衷是将签名的原始数字转换为其十六进制表示,其方式是保留数字的符号.事实证明,目前的实现LowerHex,UpperHex对于签署的原始整数和亲戚简单地将其视为无符号.无论我添加哪些额外的格式化标记,这些实现似乎只是为了格式化目的而将数字重新解释为其无符号对应物.(游乐场)

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
Run Code Online (Sandbox Code Playgroud)

文档中std::fmt不清楚这是否应该发生,或者甚至是有效的,并且UpperHex(或任何其他格式特征)没有提到有符号整数的实现将数字解释为无符号.Rust的GitHub存储库似乎也没有任何相关问题.(补遗通知后:1.24.0文件开始,文档已得到改进,以正确解决这些问题,请参阅问题#42860)

最终,人们可以为任务实现特定的功能(如下所示),不幸的是与格式化程序API不兼容.

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());
Run Code Online (Sandbox Code Playgroud)

对于有符号整数类型,这种行为是故意的吗?有没有办法在遵循标准的同时执行此格式化过程Formatter

Fra*_*gné 5

有没有办法在仍然遵循标准的情况下执行此格式化过程Formatter

是的,但是您需要创建一个新类型以提供的独特实现UpperHex。下面是一个方面的实现+#以及0标志(也可能更多,我没有测试过):

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!();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)