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,它无法破译类型?

谢谢你,埃胡德

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 为单位的数量的函数,因为所有这些类型都是相同的。

要将 B、KB、MB 等分离为不同“种类”的整数,您需要它们是 的子类型Int,而不是Int. ButInt是最终类型,因此无论如何您都不能对其进行子类型化。

一个更好的方法是只让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。您可以将对象 BKBMB等放在一个列表中,并对它们进行任何您想要的操作。

或者,您可以使单元对象本身包含有关它们的顺序或它们之间的比率的一些信息,而不是将这些信息存储在外部列表中。

您甚至可以使用此方案通过隐式转换来做一些古怪的事情。像这样的东西浮现在脑海:

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 MBor123456789 B而不是Storage(4, MB)or Storage(123456789, B)

于 2012-10-19T06:34:03.947 回答
0

在 Scala 中,类型不是值。

您可能应该为您的用例查看单例对象

于 2012-10-18T21:13:12.007 回答