5

データサイズ(バイト、KB ...)を表すタイプファミリーを作成しようとしています。そのためのアイデアは、以下に基づいて実際のサイズを持つ基本タイプを構築することです。

  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

それらの順序付きリストがあります:

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

そして、ターゲットタイプを取り、それらの間のインデックスの差を見つけ、差の累乗で1024を掛ける変換メソッドがあります。それで:

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)
  }  
}

メソッドの有効性をチェックする前に、いくつかの問題があります(Scalaは初めてです):

  • 値ではなく型を保持するリスト(または他のSeq)を作成する方法はありますか?というか、値としてタイプしますか?
  • 私が正しく理解していれば、型はコンパイルを超えて保持されません。これは、実行時にGB値を既存のKBに渡すと、型を解読できないことを意味しますか?

ありがとう、Ehud

4

2 に答える 2

9

これらのタイプはすべて、独立したタイプではなく、単なるタイプエイリアスです。

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

タイプエイリアスは、同じタイプの単なる異なる名前です。したがって、それを書くことができたとしても、あなたのリストは次のように書いたのと同じです。

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

同様に、これらのタイプはすべて同じものであるため、MB単位の数量を受け入れるために必要な関数を作成するためにこれらのタイプを使用することはできません。

IntB、KB、MBなどを整数の異なる「種類」として分離するには、のタイプエイリアスではなく、のサブタイプである必要がありますInt。ただしInt、これは最終的なタイプであるため、とにかくサブタイプ化することはできません。

はるかに優れたアプローチは、生の数値を表すだけで、代わりにユニットと一緒にInt表す型を実装することです。これにはいくつかのアプローチがありますが、私は次のようにします。Int

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)

現在、3メガバイトはStorage(3, MB)で、17バイトはStorage(17, B)です。任意の整数とStorage数量を静的に強制的に分離でき、数量がある場合は常に単位をデータオブジェクトとして使用できます(静的に推測できる必要はありません)Storageオブジェクト、、、 Bなどをリストに入れて、必要な操作を行うことができKBます。MB

または、外部リストに情報を保存するのではなく、ユニットオブジェクト自体にそれらの順序またはそれらの間の比率に関する情報を含めることができます。

このスキームを使用して、暗黙の変換で奇抜なことを行うこともできます。このようなことが頭に浮かびます:

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)
}

これで、暗黙的なものをインポートしたら、またはの代わりにまたはのようなものを簡単に書くこと4 MB123456789 BできStorage(4, MB)ますStorage(123456789, B)

于 2012-10-19T06:34:03.947 に答える
0

タイプはScalaの値ではありません。

ユースケースについては、おそらくシングルトンオブジェクトを検討する必要があります。

于 2012-10-18T21:13:12.007 に答える