我正在尝试创建一个穷人版本的 refined types 实现,对字符串内容进行简单验证,并通过另一个函数的
Implicit
证据检查返回类型。似乎类型在从 check
函数返回后被删除了。有人可以建议我一个 scala 技巧来有效地做到这一点吗?
sealed trait Validate
sealed trait Pass extends Validate
sealed trait Fail extends Validate
type SUCCESS = Pass
case class Validator[State <: Validate: TypeTag](s: String = "") {
def check = {
if (s == "awesome") {
Validator[Pass](s)
} else {
Validator[Fail](s)
}
}
def pass: Validator[Pass] = Validator[Pass](s)
def fail: Validator[Fail] = Validator[Fail](s)
def validate(implicit ev: State =:= SUCCESS): String = s
def testResult = typeOf[State] =:= typeOf[SUCCESS]
}
Validator("awesome").check.testResult // true
Validator("awesome").check.validate // Cannot prove that _1 =:= MdocApp.this.SUCCESS.
如果我正确理解了您的目标,您希望将使用
scala-reflect
TypeTag
(testResult
) 的实现替换为使用静态类型和隐式 (validate
) 的实现。
check
的返回类型只是Validator[Validate]
,而不是Validator[Pass]
或Validator[Fail]
。
类型在编译时解析,因此编译器必须在编译时知道字符串是否为
"awesome"
。例如,您可以举起 s
来打字。
类型为 String
的字符串太粗糙,您可以改用精确的单例子类型。您可以为编译时“模式匹配”引入一个类型类
// type class
trait Check[S <: String] {
type State <: Validate
}
trait LowPriorityCheck {
type Aux[S <: String, State0 <: Validate] = Check[S] {type State = State0 }
implicit def default[S <: String]: Aux[S, Fail] = null
}
object Check extends LowPriorityCheck {
implicit val pass: Aux["awesome", Pass] = null
}
case class Validator[S <: String with Singleton, State <: Validate](s: S) {
def check(implicit check: Check[S]): Validator[S, check.State] =
Validator[S, check.State](s)
def validate(implicit ev: State =:= SUCCESS): String = s
}
Validator("awesome").check.validate // awesome
Validator("abc").check.validate // Cannot prove that Fail =:= SUCCESS
如果你更愿意保留这两个实现,你可以恢复
TypeTag
上下文边界
trait Check[S <: String, State <: Validate]
trait LowPriorityCheck {
implicit def default[S <: String]: Check[S, Fail] = null
}
object Check extends LowPriorityCheck {
implicit val pass: Check["awesome", Pass] = null
}
case class Validator[S <: String with Singleton, State <: Validate: TypeTag](s: S) {
def check[St <: Validate : TypeTag](implicit
check: Check[S, St]
): Validator[S, St] = Validator[S, St](s)
def testResult = typeOf[State] =:= typeOf[SUCCESS]
def validate(implicit ev: State =:= SUCCESS): String = s
}