簡體   English   中英

Scala 中的類型細化但不使用細化

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM