2012-06-22 11 views
6

Consente di avere una classe di utilità chiamata MathUtil.Scala Numeric init con costante 0

e sembra così.

abstract class MathUtil(T:Numeric){ 
    def nextNumber(value:T) 
    def result():T 
} 

Lets ho sottoclasse in questo modo

class SumUtil[T:Numeric] extends MathUtil[T]{ 
    private var sum:T = 0 
    override def nextNumber(value:T){ 
    sum = sum + value 
    } 
    override def result():T = sum 
} 

Ho un problema con l'istruzione

private var sum:T = 0 

Ora, devo inizializzare sommare a 0. direi qualsiasi numerica avere un modo per rappresentare 0. Im abbastanza nuovo per scala. Come posso risolvere questo problema?

+0

Grazie a tutti per le risposte. Ho una domanda successiva. Diciamo che ho una classe che ha un membro overrideable di tipo MathUtils. – questionersam

risposta

11

Il Numeric type class instance ha un metodo zero che fa quello che si vuole:

class SumUtil[T: Numeric] extends MathUtil[T] { 
    private var sum: T = implicitly[Numeric[T]].zero 
    override def nextNumber(value: T) { 
    sum = implicitly[Numeric[T]].plus(sum, value) 
    } 
    override def result(): T = sum 
} 

Si noti che è necessario anche l'istanza per il metodo plus, a meno che non si importano Numeric.Implicits._, nel qual caso è possibile utilizzare +. È anche possibile pulire il codice un po ', non utilizzando il contesto legato sintassi in questo caso:

class SumUtil[T](implicit ev: Numeric[T]) extends MathUtil[T] { 
    import Numeric.Implicits._ 
    private var sum: T = ev.zero 
    override def nextNumber(value: T) { 
    sum = sum + value 
    } 
    override def result(): T = sum 
} 

Questo è esattamente equivalente: la versione contesto legato è lo zucchero sintattico per questo argomento implicito, ma se avete bisogno di usa esplicitamente questo argomento (come fai qui, per il suo zero), trovo più pulito scrivere la versione desugared.

+0

Hey Travis! È bello vederti postare qui (questo è Ben di Austin). Sfortunatamente questa roba numerica è, IMO, semplicemente completamente fugace. Si scopre che è anche lento come l'inferno. IMO l'intero meccanismo implicito di Scala è goffo, fragile e difficile da comprendere e hai ancora bisogno di altre cianfrusaglie come @specialized, che è anche gravemente compromesso. Penso che questa roba sarebbe espressa molto meglio usando la specializzazione in classi di stile C++, che * * * funzionerebbe * esattamente come tutti si aspettano, essenzialmente copiando l'implementazione con s/int/double/o qualsiasi altra cosa. –

+0

@UrbanVagabond: Ciao, Ben! Sono d'accordo sul fatto che 'Numeric' è un disastro, e non riesco a ricordare l'ultima volta che l'ho usato nel mio codice, ma non penso che il problema sia il modo in cui Scala implementa le classi di tipi (che sono effettivamente cresciute piacere). –

0

Penso che ci sia bisogno di essere un piccolo chiarimento di esattamente quello che stai cercando di realizzare. Dai documenti Scala, il tipo numerico stesso è generico. Il mio sentimento qui è ciò che in realtà vuoi è descrivere un'astrazione MathUtil che gestisce qualsiasi [T] numerico piuttosto che sottoclassi di Numeric [_], che è ciò che il tuo codice sta attualmente descrivendo. Ecco l'implementazione corretta basata su tale assunto.

//Define a MathUtil that works on any T 
abstract class MathUtil[T] { 
    def nextNumber(value: T) 
    def result(): T 
} 

//Define a SumUtil that works on any T that has an available Numeric 
//Will search implicit scope, but also allows you to provide an 
//implementation if desired. 
class SumUtil[T](implicit n: Numeric[T]) extends MathUtil[T] { 
    //Use the Numeric to generate the zero correctly. 
    private var sum: T = n.zero 
    //Use the Numeric to correctly add the sum and value 
    override def nextNumber(value: T) = sum = n.plus(sum, value) 
    override def result(): T = sum 
} 

//Test that it works. 
val a = new SumUtil[Int] 
val b = List(1,2,3) 

b map a.nextNumber //Quick and dirty test... returns a meaningless list 
println(a.result) //Does indeed print 6 

Se quanto sopra non fa quello che vuoi, chiarisci la tua domanda.

+0

Non hai ragione ... '[T: Numeric]' è un contesto vincolato e si espanderà a '[T] (implicito n: Numerico [T])', quindi il tuo codice è quasi lo stesso degli OP tranne per il 'n.zero'. – drexin

Problemi correlati