如何为所有Integer类型创建通用的整数到十六进制函数?

时间:2014-12-24 17:12:28

标签: generics swift

我想为所有整数类型创建一个Integer-to-Hex函数。

对于1字节的Int8,它返回两个字母,例如0A

对于2字节的Int16,它返回四个字母,例如0A0B

对于8字节的Int64,它返回16个字母,例如0102030405060708

func hex(v: Int) -> String {
    var s = ""
    var i = v
    for _ in 0..<sizeof(Int)*2 {
        s = String(format: "%x", i & 0xF) + s
        i = i >> 4
    }
    return s
}

func hex(v: Int64) -> String {
    var s = ""
    var i = v
    for _ in 0..<sizeof(Int64)*2 {
        s = String(format: "%x", i & 0xF) + s
        i = i >> 4
    }
    return s
}

func hex(v: Int32) -> String {
    var s = ""
    var i = v
    for _ in 0..<sizeof(Int32)*2 {
        s = String(format: "%x", i & 0xF) + s
        i = i >> 4
    }
    return s
}

func hex(v: Int16) -> String {
    var s = ""
    var i = v
    for _ in 0..<sizeof(Int16)*2 {
        s = String(format: "%x", i & 0xF) + s
        i = i >> 4
    }
    return s
}

func hex(v: Int8) -> String {
    var s = ""
    var i = v
    for _ in 0..<sizeof(Int8)*2 {
        s = String(format: "%x", i & 0xF) + s
        i = i >> 4
    }
    return s
}

上面的代码工作正常。

然后我尝试创建这样的通用版本:

func hex<T: IntegerType>(v: T) -> String {
    var s = ""
    var i = v
    for _ in 0..<sizeof(T)*2 {
        s = String(format: "%x", i & 0xF) + s
        i = i >> 4
    }
    return s
}

编译此代码时,我收到错误:T无法转换为Int

完成此任务的正确方法是什么?

5 个答案:

答案 0 :(得分:3)

非常简单的解决方案是将输入值与IntMax合并为.toIntMax()。:

func hex<T: IntegerType>(v: T) -> String {
    var s = ""
    var i = v.toIntMax()
    for _ in 0..<sizeof(T)*2 {
        s = String(format: "%x", i & 0xF) + s
        i >>= 4
    }
    return s
}

注意:这仅适用于0...Int64.max个值。


但是,我会这样做:

func hex<T: IntegerType>(v: T) -> String {
    return String(format:"%0\(sizeof(T) * 2)x", v.toIntMax())
}

注意:这仅适用于0...UInt32.max个值。


已添加:这适用于所有可用的整数类型/值。

func hex<T:IntegerType>(var v:T) -> String {
    var s = ""
    for _ in 0..<sizeof(T) * 2 {
        s = String(format: "%X", (v & 0xf).toIntMax()) + s
        v /= 16
    }
    return s
}
  • .toIntMax()T转换为具体的整数类型。
  • / 16代替>> 4

答案 1 :(得分:2)

您的问题并不清楚为什么您没有使用已经为您执行此操作的内置初始化程序:

let i = // some kind of integer
var s = String(i, radix:16)

如果你不喜欢s的结果格式,那么大写它并用额外的字符填充它比完成你在这里所做的所有工作肯定要容易得多。

答案 2 :(得分:2)

这里的问题是,虽然为所有整数类型定义了>>,但IntegerType并不保证其存在。 IntegerType符合IntegerArithmeticType+-等,BitwiseOperationsType符合&|但是它看起来不像>>

有点躲闪,但你可以使用新的协议扩展整数,让我们说Shiftable,然后要求:

protocol Shiftable {
    func >>(lhs: Self, rhs: Self) -> Self
    // + other shifting operators
}

extension Int: Shiftable {
  // nothing actually needed here
}

extension Int16: Shiftable { } // etc

// still need IntegerType if you want to do other operations
// (or alternatively Shiftable could require IntegerType conformance)
func shiftIt<I: protocol<IntegerType, Shiftable>>(i: I) {
    println(i+1 >> 4)
}

shiftIt(5000)
shiftIt(5000 as Int16)

编辑:oop,与String(format: ...)看起来类似的麻烦,这是我能想到的最好的:

edit2:正如@rintaro ponts .toIntMax()是解决这个问题的一种简单方法,但它有点让人想到如何让它完全正常工作:-)

func hex<T: protocol<IntegerType,Shiftable>>(v: T) -> String {

    // In creating this dictionary, the IntegerLiterals should
    // be converted to type T, which means you can use a type
    // T to look them up.  Hopefully the optimizer will only
    // run this code once per version of this function...
    let hexVals: [T:Character] = [
        0:"0", 1:"1", 2:"2", 3:"3", 4:"4",
        5:"5", 6:"6", 7:"7", 8:"8", 9:"9",
        10:"A", 11:"B", 12:"C", 13:"D", 14:"E", 15:"F"
    ]

    var chars: [Character] = []
    var i = v
    for _ in 0..<sizeof(T)*2 {
        chars.append(hexVals[(i & 0xF)] ?? "?")
        i = i >> 4
    }
    return String(lazy(chars).reverse())
}

答案 3 :(得分:0)

谢谢大家的意见。

我创建的通用函数的第一个版本是:

func hex<T: UnsignedIntegerType>(v: T) -> String {
    var fmt = "%0\(sizeof(T)*2)"
    fmt += (sizeof(T) > 4) ? "llx" : "x"
    return String(format: fmt, v.toUIntMax())
}

func hex<T: SignedIntegerType>(v: T) -> String {
    var fmt = "%0\(sizeof(T)*2)"
    fmt += (sizeof(T) > 4) ? "llx" : "x"
    return String(format: fmt, v.toIntMax())
}

我使用以下代码测试两个函数

println("=== 64-bit ===")
println(hex(UInt64.max))
println(hex(UInt64.min))
println(hex(Int64.max))
println(hex(Int64.min))

println("=== 32-bit ===")
println(hex(UInt32.max))
println(hex(UInt32.min))
println(hex(Int32.max))
println(hex(Int32.min))

println("=== 16-bit ===")
println(hex(UInt16.max))
println(hex(UInt16.min))
println(hex(Int16.max))
println(hex(Int16.min))

println("=== 8-bit ===")
println(hex(UInt8.max))
println(hex(UInt8.min))
println(hex(Int8.max))
println(hex(Int8.min))

16位和8位负整数的输出显然是错误的。

=== 64-bit ===
ffffffffffffffff
0000000000000000
7fffffffffffffff
8000000000000000
=== 32-bit ===
ffffffff
00000000
7fffffff
80000000
=== 16-bit ===
ffff
0000
7fff
ffff8000
=== 8-bit ===
ff
00
7f
ffffff80

这是由%x说明符引起的,它只需要32位整数。它会为负Int8和Int16生成错误的输出。

String(format: '%x', Int16.min)   // outputs ffff8000
String(format: '%x', Int8.min)    // outputs ffffff80

第二种方法是使用按位运算符:

func hex<T: SignedIntegerType>(v: T) -> String {
    var s = ""
    var i = v.toIntMax()
    for _ in 0..<sizeof(T)*2 {
        s = String(format: "%x", i & 0xF) + s
        i = i >> 4
    }
    return s
}

func hex<T: UnsignedIntegerType>(v: T) -> String {
    var s = ""
    var i = v.toUIntMax()
    for _ in 0..<sizeof(T)*2 {
        s = String(format: "%x", i & 0xF) + s
        i = i >> 4
    }
    return s
}

到目前为止,它们似乎对所有整数都是正常的,消极的和积极的。测试代码输出:

=== 64-bit ===
ffffffffffffffff
0000000000000000
7fffffffffffffff
8000000000000000
=== 32-bit ===
ffffffff
00000000
7fffffff
80000000
=== 16-bit ===
ffff
0000
7fff
8000
=== 8-bit ===
ff
00
7f
80

答案 4 :(得分:0)

作为Swift 2协议扩展方法的另一种可能的解决方案, 使用<inttypes.h>中的打印宽度修饰符常量:

extension IntegerType where Self: CVarArgType {
    var hex : String {
        let format : String
        switch (sizeofValue(self)) {
        case 1:
            format = "%02" + __PRI_8_LENGTH_MODIFIER__ + "X"
        case 2:
            format = "%04" + PRIX16
        case 4:
            format = "%08" + PRIX32
        case 8:
            format = "%016" + __PRI_64_LENGTH_MODIFIER__ + "X"
        default:
            fatalError("Unexpected integer size")
        }
        return String(format: format, self)
    }
}

这适用于所有已签名和未签名的全部范围 整数类型:

UInt8.max.hex // FF
Int8.max.hex  // 7F
Int8.min.hex  // 80

UInt16.max.hex // FFFF
Int16.max.hex  // 7FFF
Int16.min.hex  // 8000

UInt32.max.hex // FFFFFFFF
Int32.max.hex  // 7FFFFFFF
Int32.min.hex  // 80000000

UInt64.max.hex // FFFFFFFFFFFFFFFF
Int64.max.hex  // 7FFFFFFFFFFFFFFF
Int64.min.hex  // 8000000000000000

Swift 3的更新:

extension Integer where Self: CVarArg {
    var hex : String {
        let format : String
        switch MemoryLayout.size(ofValue: self) {
        case 1:
            format = "%02" + __PRI_8_LENGTH_MODIFIER__ + "X"
        case 2:
            format = "%04" + PRIX16
        case 4:
            format = "%08" + PRIX32
        case 8:
            format = "%016" + __PRI_64_LENGTH_MODIFIER__ + "X"
        default:
            fatalError("Unexpected integer size")
        }
        return String(format: format, self)
    }
}