![](/img/trans.png)
[英]How to ensure type safety with Scala's Refined library when using the same predicate for refinement
[英]Type refinements in Scala but without using refined
我正在嘗試創建一個基於 String 的 HexString 類型,它應該滿足“它只包含十六進制數字”的條件,如果可能的話,我想讓編譯器為我檢查它。
一個明顯的解決方案是使用細化並編寫如下內容:
type HexString = String Refined MatchesRegex[W.`"""^(([0-9a-f]+)|([0-9A-F]+))$"""`.T]
refineMV[MatchesRegex[W.`"""^(([0-9a-f]+)|([0-9A-F]+))$"""`.T]]("AF0")
現在,我並不反對提煉,只是我覺得它對於我正在嘗試做的事情有點矯枉過正(並且不知道我是否會在其他地方使用它)而且我不願意導入一個我不確定總體上會使用超過一兩次的庫,並帶來可能看起來像魔術的語法(如果不是對我來說,對團隊中的其他開發人員來說)。
另一方面,我可以用純 Scala 代碼編寫的最好的代碼是帶有智能構造函數的值 class,這一切都很好,對我來說感覺很輕,除了我不能進行編譯時類型檢查。 目前看起來像這樣:
final case class HexString private (str: String) extends AnyVal {
// ...
}
object HexString {
def fromStringLiteral(literal: String): HexString = {
def isValid(str: String): Boolean = "\\p{XDigit}+".r.pattern.matcher(str).matches
if (isValid(literal)) HexString(literal)
else throw new IllegalArgumentException("Not a valid hexadecimal string")
}
}
對於大多數代碼庫,運行時檢查就足夠了; 但是,我可能需要在某些時候進行編譯時檢查,而且似乎沒有辦法實現它,除非使用細化。
如果我可以在不引入太多魔法的情況下使代碼盡可能本地化和易於理解,是否可以使用宏並指示編譯器針對正則表達式測試賦值的 RHS,並取決於它是否匹配,它會創建 HexString 的實例或吐出編譯器錯誤?
val ex1: HexString = "AF0" // HexString("AF0")
val ex2: HexString = "Hello World" // doesn't compile
除了我使用 Scala 元編寫的 ADT 遍歷和轉換程序之外,我真的沒有使用 Scala 宏的經驗。
如果您希望fromStringLiteral
在編譯時工作,您可以將其設為宏(請參閱 sbt設置)
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def fromStringLiteral(literal: String): HexString = macro fromStringLiteralImpl
def fromStringLiteralImpl(c: blackbox.Context)(literal: c.Tree): c.Tree = {
import c.universe._
val literalStr = literal match {
case q"${s: String}" => s
case _ => c.abort(c.enclosingPosition, s"$literal is not a string literal")
}
if (isValid(literalStr)) q"HexString($literal)"
else c.abort(c.enclosingPosition, s"$literalStr is not a valid hexadecimal string")
}
然后
val ex1: HexString = HexString.fromStringLiteral("AF0") // HexString("AF0")
//val ex2: HexString = HexString.fromStringLiteral("Hello World") // doesn't compile
如果你想讓它像這樣工作
import HexString._
val ex1: HexString = "AF0" // HexString("AF0")
//val ex2: HexString = "Hello World" // doesn't compile
然后您還可以使fromStringLiteral
成為隱式轉換
implicit def fromStringLiteral(literal: String): HexString = macro fromStringLiteralImpl
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.