2013-11-20 12 views
5

Utilizzando go1.1.2 Win64, ho un programma Go che "esegue il marshalling" è una struttura contenente un float64. Quando il valore del float64 non è un numero intero es. 1234.44, quindi diventa "maresciallo" ed come galleggiante (json.Marshal). Quando invece è un numero intero es. "1234.00" viene eseguito come numero intero "1234". Quando lo ricevo all'altra estremità (Dart), Dart (30188) tratta l'intero numero come intero (nella mappa - JSON.decode). Di conseguenza, il programma Dart si interrompe quando la rappresentazione dei dati float (double) non contiene un punto decimale, e io cerco di "estrarla" dalla mappa come una doppia.Go esegue correttamente il marshal float64 su JSON?

Questo può ovviamente essere risolto in diversi modi (ad esempio, convertire in numero intero e quindi riconvertire in float), tuttavia mi sono chiesto se c'è un altro (migliore) modo di gestire questa situazione.

C'è un altro modo migliore per gestire questo rispetto a convertire float64 in intero?

risposta

5

JSON, proprio come Javascript, non differisce tra numeri interi e numeri.

Se Dart tratta 1234.00 in modo diverso da 1234, quindi sta facendo delle ipotesi sul valore non supportato dallo JSON specification.

Mentre Go effettivamente maresciallo float64 correttamente, un modo di ottenere intorno al problema con assunzione di Dart è implementando il Marshaler interface sul proprio tipo:

type Number float64 

func (n Number) MarshalJSON() ([]byte, error) { 
    // There are probably better ways to do it. It is just an example 
    return []byte(fmt.Sprintf("%f", n)), nil 
} 

e quindi è possibile utilizzare il proprio Number tipo, invece di float64, nelle strutture che farai Maresciallo. In questo modo puoi assicurarti che i tuoi numeri vengano sempre sottoposti al marshalling con un punto decimale.

esempio Lavorare su Playground

+0

Grazie per la soluzione. Penso che questo dovrebbe essere risolto sulla fine del dardo. Sembra che un numero intero non possa essere assegnato a un doppio in Dart. Mi sembra un'anomalia, ma accetto di essermi sbagliato almeno da una prospettiva teorica (cast-up, cast-down, ecc.). La soluzione che attualmente ho è la seguente: "double dAcctBal = (mAcctData ['D_AcctBal'] come num)/1;" (dove mAcctData è la mappa in cui "D_AcctBal" può essere un numero intero o un doppio a seconda che si tratti di un numero intero). Questa soluzione mi sembra un po 'incisiva, ma se un intero non può essere assegnato direttamente a un doppio? –

+0

Sì, sono d'accordo che sarebbe meglio risolverlo sul dardo fine. Vi sarei anche felice di darvi una soluzione del genere se lo sapessi, ma la mia esperienza con Dart è * molto * limitata. Forse qualcuno con più conoscenza può trovare una soluzione Dart più idiomatica. – ANisus

+0

JSON non specifica la semantica dei suoi numeri letterali, quindi non è più corretto usare il doppio rispetto agli interi. Dart ha due tipi di numeri.Tutto ciò che contiene un punto decimale o una parte esponenziale deve essere un doppio, e tutto il resto viene analizzato come un numero intero, che in Dart fornisce più precisione del doppio. Ciò conserva quante più informazioni possibili dal numero JSON. Richiede di usare manualmente .toDouble se vuoi che tutti i numeri siano raddoppiati. – lrn

1

Quanto segue sembra essere (per me) la soluzione. Il metodo intero toDouble() funziona anche con "num" (o viceversa). Mi sembra che quando si lavora con json e valori monetari che possono essere interpretati come DART o double o int, è necessario usare "as num" e quindi usare il metodo built-in to Double().

Esempio (Go):

type cuAcctRow struct { 
     ..... 
    D_AcctBal float64 
     ..... 
} 
    if baJsAcctDet, oOsError = json.Marshal(uAcctRow); oOsError != nil { 

Esempio (Dart):

Map mAcctData = json.parse(sResponse); 

double dAcctBal = (mAcctData['D_AcctBal'] as num).toDouble(); 

Non so perché Dart non consente l'assegnazione diretta di interi per raddoppiare, ma sono certo c'è una buona ragione

+0

Un ottimo motivo. Le annotazioni di tipo in Dart sono facoltative e vengono trattate come asserzioni (vengono ignorate nella modalità di produzione). Ciò significa che una variabile non ha un tipo, quindi l'assegnazione di un intero a una variabile dichiarata come double deve funzionare allo stesso modo se la variabile è dichiarata double ("double x") o semplicemente dynamic ("var x"). Ciò impedisce qualsiasi conversione implicita. In modalità selezionata, l'assegnazione viene verificata e poiché 'int' non è un sottotipo di 'double', l'asserzione di tipo fallisce. Devi fare un esplicito n.toDouble(). – lrn

+0

@lrn: Grazie per la spiegazione. Io "dovrei" studiarlo. Mi ha lasciato perplesso, ma immagino ci siano alcuni fattori coinvolti. Mentre mi sono spostato da questo per ora, presumo che la mia piccola "soluzione" sia OK. (come num) .toDouble() non è molto oneroso, tuttavia, da un punto di vista pratico, mi è sembrato strano che un int che è perfettamente compatibile nel range di un double non possa essere assegnato direttamente ad un double. Per quanto relativamente semplice come questo piccolo problema, ci sono alcuni fattori coinvolti (incluso JS credo - forse indirettamente). –