Ehu*_*dor 5 scala typelist custom-type
我期待创建一个表示数据大小(字节,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
Run Code Online (Sandbox Code Playgroud)
有一个有序的列表:
val sizes = List(B, KB, MB, GB, TB, PB, EX, ZB, TB)
Run Code Online (Sandbox Code Playgroud)
并且有一个转换方法,它采用目标类型,找到它们之间的索引差异,并乘以差异的幂乘以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)
}
}
Run Code Online (Sandbox Code Playgroud)
在我检查方法的有效性之前我有一些问题(因为我是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
Run Code Online (Sandbox Code Playgroud)
类型别名只是同一类型的不同名称.所以即使你可以写它,你的列表也相当于写了:
val sizes = List(Int, Int, Int, Int, Int, Int, Int, Int, Int)
Run Code Online (Sandbox Code Playgroud)
同样地,您永远不能使用这些类型来编写接受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)
Run Code Online (Sandbox Code Playgroud)
现在是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)
}
Run Code Online (Sandbox Code Playgroud)
就这样,一旦你已经导入了隐式的,你可以简单地写东西像4 MB或123456789 B代替Storage(4, MB)或Storage(123456789, B).