在列表中使用自定义scala类型
我希望创建一个表示数据大小(字节、KB…)的类型族。为此,我们的想法是构建一个基本类型,使其具有基于以下各项的实际大小:在列表中使用自定义scala类型,scala,custom-type,typelist,Scala,Custom Type,Typelist,我希望创建一个表示数据大小(字节、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 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)
}
}
def convertTo(目标类型:SizeUnit):SizeUnit={
def电源(itr:Int):Int={
如果(itr==0)1
else 1024*功率(itr-1)
}
val距离=size.indexOf(targetType)-size.indexOf(this)
距离赛{
//相同类型-相同值
案例0=>targetType
//正距离表示较大的单位-较小的数字
案例x>0=>targetType/power(距离)
//负距离意味着更小的单位-更大的数字,并注意负性
案例x目标类型*功率(距离)*(-1)
}
}
在检查该方法的有效性之前,我遇到了一些问题(因为我是Scala新手):
- 有没有办法创建一个保存类型而不是值的列表(或任何其他Seq)?或者更确切地说-类型作为值
- 如果我理解正确,类型不会超出编译范围。这是否意味着在运行时,如果我将一个GB值传递给现有的KB,它就无法破译类型
Ehud类型不是Scala中的值
您可能应该查看您的用例。所有这些类型都只是类型别名,而不是独立的类型
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
的别名。但是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兆字节是存储(3,MB)
,17兆字节是存储(17,B)
。在任意整数和存储
数量之间有一个很好的静态强制分隔,并且每当有存储
数量时,总是将单位作为数据对象(无需静态推断)。您可以将对象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)
}
这样,一旦你导入了隐式,你就可以简单地编写
4MB
或123456789b
而不是Storage(4MB)
或Storage(123456789,B)
,这些都是好主意,但它们并不能解决我的主要问题,即如何在不硬编码每个人所需电源的情况下进行转换,例如def toB(storage:storage)storage.unit match{case KB=>storage.num*1024….@EhudKaldor如果B
,KB
,MB
,等等是对象,而不是类型,你可以对它们做任何事情。例如,你可以构造列表列表(B,KB,MB…)
,并有一个函数转换(数量:存储,单位:SizeUnit):使用两个SizeUnit
值列表中的位置来计算它们之间的比率的存储。