2012-10-18 12 views
5

Ich bin auf der Suche nach einer Typfamilie, die Datengrößen (Byte, KB ...) darstellen würde. denn das ist die Idee, einen Basistyp zu bauen, um die realen Größen zu haben, basierend auf:mit benutzerdefinierten Scala-Typen in der Liste

type SizeUnit = Int 
    type B = SizeUnit 
    type KB = SizeUnit 
    type MB = SizeUnit 
    type GB = SizeUnit 
    type TB = SizeUnit 
    type PB = SizeUnit 
    type EB = SizeUnit 
    type ZB = SizeUnit 
    type YB = SizeUnit 

haben eine geordnete Liste von ihnen:

val sizes = List(B, KB, MB, GB, TB, PB, EX, ZB, TB) 

und hat eine convertion Methode, die einen Zieltyp nimmt , findet die Indexdifferenz zwischen ihnen und multipliziert mit 1024 in der Potenz der Differenz. so:

def convertTo(targetType: SizeUnit): SizeUnit ={ 
    def power(itr: Int): Int = { 
    if (itr == 0) 1 
    else 1024*power(itr-1) 
    } 

    val distance = sizes.indexOf(targetType) - sizes.indexOf(this) 
    distance match { 
    //same type - same value 
    case 0 => targetType 
    //positive distance means larget unit - smaller number 
    case x>0 => targetType/power(distance) 
    //negative distance means smaller unit - larger number and take care of negitivity 
    case x<0 => targetType * power(distance) * (-1) 
    } 
} 

ich habe ein paar Probleme, bevor ich sogar die Gültigkeit des Verfahrens prüfen (wie ich bin neu in Scala):

  • ist es eine Möglichkeit, eine Liste (oder eine andere zu schaffen Seq), die Typen statt Werte hält? oder vielmehr - Typen als Werte?
  • Wenn ich richtig verstehe, werden Typen nicht über Kompilierung gehalten. bedeutet das, dass in der Laufzeit, wenn ich einen GB-Wert an eine vorhandene KB übergebe, es die Typen nicht entschlüsseln kann?

danke, Ehud

Antwort

7

Alle diese Typen sind einfach Aliase, keine unabhängigen Typen.

scala> type SizeUnit = Int 
defined type alias SizeUnit 

scala> type B = SizeUnit 
defined type alias B 

scala> type KB = SizeUnit 
defined type alias KB 

scala> (3 : KB) == (3 : B) 
res0: Boolean = true 

Typ Aliase sind einfach verschiedene Namen für den gleichen Typ. Also selbst wenn Sie es schreiben könnte, die Liste wäre gleichbedeutend mit geschrieben zu haben:

val sizes = List(Int, Int, Int, Int, Int, Int, Int, Int, Int) 

Und in ähnlicher Weise könnten Sie nie diese Art verwenden, um eine Funktion zu schreiben, die erforderlich ist, eine Menge in MB zu übernehmen, da alle Diese Typen sind das Gleiche.

Um B, KB, MB usw. als verschiedene "Arten" von Integer zu trennen, müssten sie Untertypen von Int sein, geben Sie keine Aliase für Int ein. Aber Int ist ein endgültiger Typ, also können Sie ihn nicht unterschreiben.

Ein viel besserer Ansatz ist es, nur lassen Int eine rohe Zahl darstellen, und stattdessen eine Art zu implementieren, die mit eine Einheit ein Intzusammen darstellt. Es gibt mehrere Ansätze, die Sie für das nehmen, aber ich würde es so etwas tun:

abstract class SizeUnit 

case object B extends SizeUnit 
case object KB extends SizeUnit 
case object MB extends SizeUnit 


case class Storage(num : Int, unit : SizeUnit) 

Jetzt 3 Megabyte ist Storage(3, MB) und 17 Byte Storage(17, B) ist. Sie haben eine schöne statisch erzwungene Trennung zwischen beliebigen ganzen Zahlen und Storage Mengen, und Sie haben immer die Einheit als Datenobjekt (keine Notwendigkeit, es statisch abzuleiten), wenn Sie eine Storage Menge haben. Sie können die ObjekteB, KB, MB, etc. in eine Liste setzen und tun, was auch immer Manipulation mit ihnen Sie wollen.

Alternativ können Sie das Gerät machen Objekte selbst einige Informationen über ihre Bestellung oder Verhältnisse zwischen ihnen enthalten, anstatt diese Informationen in einer externen Liste zu speichern.

Sie können sogar verrückte Dinge mit impliziten Konvertierungen mit diesem Schema tun. So etwas wie dies in den Sinn:

object SizeableInt { 
    // since I want to give the conversion methods the same name as the 
    // units, I need different names to refer to the units in the 
    // implementation of those methods. If B, KB, etc were defined in 
    // a different qualified namespace, this wouldn't be necessary. 
    private val _B = B 
    private val _KB = KB 
    private val _MB = MB 

    case class SizeableInt(x : Int) { 
     def B : Storage = Storage(x, _B) 
     def KB : Storage = Storage(x, _KB) 
     def MB : Storage = Storage(x, _MB) 
    } 

    implicit def makeSizeableInt(x : Int) : SizeableInt = SizeableInt(x) 
} 

Damit sobald Sie die implizite importiert haben, können Sie einfach Dinge wie 4 MB oder 123456789 B statt Storage(4, MB) oder Storage(123456789, B) schreiben kann.

+0

diese gute Ideen sind, aber sie haben nicht mein Hauptproblem lösen, das ist, wie die Konvertierung zu tun, um die Leistung ohne hartzucodieren das jedes Bedürfnis, wie def TOB (Lagerung: Storage) storage.unit Spiel {case KB => storage.num * 1024 .... –

+0

@EhudKaldor Wenn 'B',' KB', 'MB', etc sind * Objekte *, nicht * Typen *, können Sie alles zu ihnen tun. Sie können zum Beispiel konstruieren die Liste 'List (B, KB, MB, ...)', und hat eine Funktion 'convert (Menge: Lagerung, Einheit: SizeUnit): Storage', die die Positionen in der Liste verwendet von die zwei "SizeUnit" -Werte, die beteiligt sind, um das Verhältnis zwischen ihnen zu berechnen. – Ben

0

Typen in Scala nicht Werte sind.

Sie sollten wahrscheinlich singleton objects für Ihren Anwendungsfall betrachten.

Verwandte Themen