如何提前指定无形单件类型

时间:2017-05-26 17:32:38

标签: scala shapeless

我想构建类似LimitedString[Limit]的类型,其中Limit是字符串最大长度的类型表示。

它将按照

的方式工作
class LimitedString[Limit] [private](val s: String)
object LimitedString {
  private def getLimit[Limit]: Int = ??? // turn `Limit` type into a value
  def truncate[Limit](s: String) = new LimitedString[Limit](s take getLimit)
  def get[Limit](s: String) = 
    if(s.length < getLimit) Some(new LimitedString[Limit](s))
    else None
}

type Str100 = LimitedString[100] // obviously this won't work
def someLibraryMethod(s: Str100) = { ... }

我能弄清楚的是如何在Limit中实际键入(如在键盘中)类型(如编辑中)。

我开始研究Shapeless的单身类型,发现你可以说

100.narrow
// res1: Int(100) = 100

但如果我尝试使用Int(100)作为类型,我会收到错误。

val x: Int(100) = 100
// error: ';' expected but '(' found.

此外,我将如何实现def getLimit[Limit]: Int

之类的内容

1 个答案:

答案 0 :(得分:2)

我接受了@ TravisBrown的建议来调查Shapless的Witness,并想出了这个:

class LimitedString[Limit <: Int] private[util](val s: String) extends AnyVal {
    override def toString = s
}
class LimitedStringCompanion[Limit <: Int : Witness.Aux]{
    def limit: Int = implicitly[Witness.Aux[Limit]].value

    def unapply(s: String): Option[LimitedString[Limit]] = {
        if(s.length > limit) None else Some(new LimitedString(s))
    }

    def truncate(s: String): LimitedString[Limit] = new LimitedString(s take limit)
}

用法:

import shapeless._

object MyLibraryThing {
  type Name = LimitedString[Witness.`50`.T]
  object Name extends LimitedStringCompanion[Witness.`50`.T]

  def rename(id: Int, name: Name) = { ... }
}

使其发挥作用的关键因素:

  • Witness.Aux是一个类型类,可以用来将单个value退出类型
  • 单例类型Witness.`50`.T实际上是Int
  • 的子类型
  • 类型别名可以更方便地与
  • 进行交互