2016-10-12 4 views
0

Я играю с ходу, но не могу понять это. вот надуманный пример того, что я хочу сделать. В принципе, у меня есть номер, хранящийся в типе данных interface{}, и я хочу записать это двоичное представление числа указанного пользователем размера.go casting interface {} to numbers

func main() { 
    buf := new(bytes.Buffer) // imported from encoding.binary 
    var val1 uint64 = 0xff // 8 bytes 
    var val2 float32 = 9.876 // 4 bytes 

    var a interface{} = val1 
    var b interface{} = val2 

    // for argument sake, lets assume we want to write a as a uint8 
    // to our binary file 
    foo(buf.Bytes(), a, 1) 

    // let's write b as a float64 to our binary file 
    foo(buf,Bytes(), b, 8) 

    // write buffer to file 
    ... 
} 

// write the number in binary to the buffer 
var foo (buf *bytes.Buffer, num interface{}, sizeInBytes int) { 

    // TODO: somehow i need to convert num to the correct datatype 
    //  let's assume the first scenario where num is unit64 and 
    //  i need to make it uint8 
    var tmp uint8 = num.(uint8) // error interface is uint64, not uint8 
    var tmp uint8 = uint8(num) // error (type interface {}) to type uint8: need type assertion 

    // help please ^^^^^^ i assume writing a float32 as a float64 would 
    // follow the same paradigm 

    binary.Write(buf, binary.LittleEndian, num) 
} 
+0

Можете ли вы показать пример того, что вы ожидаете получить? 'binary.Write' уже принимает' interface {} 'и утверждает правильный тип внутри. – JimB

+0

правый, не делает. но в моем примере, если я передаю 'a' (по сути,' uint64', он будет писать 0x00000000000000FF), однако я бы хотел, чтобы в файл было записано только 0xFF. – mike

+3

Если вызывающий абонент знает размер, который они хотят во время вызова, почему бы не преобразовать его на место, а не оставить 'foo' для перечисления всех возможных комбинаций? (есть также двоичные кодировки Varint, которые используют как можно меньше места). В противном случае вы получите некоторую копию и вставку, которая выглядит так: https://play.golang.org/p/koL6_PB3Ie и не может быть действительно декодирована без первоначальных комбинаций типов и размеров и порядка. – JimB

ответ

0

Независимо от того, что вам нужно будет указывать конкретный тип для каждого значения, чтобы работать с ним численно. Поскольку преобразование меньших целых типов является просто усечением, вы можете кодировать все целочисленные значения как uint64, чтобы уменьшить количество случаев, которые вам нужно обрабатывать, а затем разрезать срез на нужное количество бит.

func foo(buf *bytes.Buffer, num interface{}, sizeInBytes int) { 
    switch sizeInBytes { 
    case 1, 2, 4, 8: 
     // OK 
    default: 
     panic("invalid size") 
    } 

    b := make([]byte, 8) 
    var un uint64 

    switch n := num.(type) { 
    case float32: 
     switch sizeInBytes { 
     case 4: 
      un = uint64(math.Float32bits(n)) 
     case 8: 
      un = math.Float64bits(float64(n)) 
     default: 
      panic("can't do that") 
     } 

    case float64: 
     switch sizeInBytes { 
     case 4: 
      un = uint64(math.Float32bits(float32(n))) 
     case 8: 
      un = math.Float64bits(n) 
     default: 
      panic("can't do that") 
     } 
    case int8: 
     un = uint64(n) 
    case uint8: 
     un = uint64(n) 
    case uint16: 
     un = uint64(n) 
    case int16: 
     un = uint64(n) 
    case uint32: 
     un = uint64(n) 
    case int32: 
     un = uint64(n) 
    case uint64: 
     un = uint64(n) 
    case int64: 
     un = uint64(n) 
    case int: 
     un = uint64(n) 
    } 

    binary.LittleEndian.PutUint64(b, un) 
    b = b[:sizeInBytes] 
    buf.Write(b) 
} 

https://play.golang.org/p/g6d5Bt1esI

+0

спасибо! @JimB :) – mike