我正在嘗試將 Exercism 的 Scala 軌道移植到 Scala 3。目前停留在“testgen”子專案上,因為我幾乎沒有反射和宏的經驗。這個 Scala 2 方法似乎可以確保在字串化結果之前可以將 String 強制轉換為文字常量?
它在KinderGardenTestGenerator和 WordCountTestGenerator 中使用,大概是為了清理學生的輸入?
所以我想在 Scala 3 中用類似的東西替換它
def escape(raw: String): String = {
Literal(StringConstant(Expr(e))).toString
}
它似乎可以訪問您需要的反射方法(using Quotes)
并執行您需要使用inline
的。
我最接近解決方案的是這個,將方法拆分為它們自己的物件:
import scala.quoted.*
object Escaper {
inline def escape(inline raw: String): String = ${literalize('{raw})}
def literalize(e: Expr[String])(using Quotes): Expr[String] = {
import quotes.reflect.*
Expr(Literal(StringConstant(e.valueOrAbort)).toString)
}
}
它似乎可以編譯,但是一旦到達編譯 KinderGardenTestGenerator 就會失敗,我收到以下錯誤:
[error] -- Error: /home/larsw/projects/scala/testgen/src/main/scala/KindergartenGardenTestGenerator.scala:33:47
[error] 33 | s"""Garden.defaultGarden(${escape(diagram.toString)}).$property("$student")"""
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^
[error] | Could not find class testgen.Escaper$ in classpath
[error] |----------------------------------------------------------------------------
[error] |Inline stack trace
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from Escaper.scala:8
[error] 8 | inline def escape(inline raw: String): String = ${literalize('{raw})}
[error] | ^^^^^^^^^^^^^^^^^^^^^
[error] ----------------------------------------------------------------------------
[error] -- Error: /home/larsw/projects/scala/testgen/src/main/scala/WordCountTestGenerator.scala:25:37
[error] 25 | val sentence = Escaper.escape(args("sentence").toString)
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] | Could not find class testgen.Escaper$ in classpath
[error] |----------------------------------------------------------------------------
[error] |Inline stack trace
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from Escaper.scala:8
[error] 8 | inline def escape(inline raw: String): String = ${literalize('{raw})}
[error] | ^^^^^^^^^^^^^^^^^^^^^
[error] ----------------------------------------------------------------------------
而且感覺行內有點矯枉過正,我的用例不是那么先進,我不需要生成代碼。我的問題是:
- 有沒有辦法在沒有宏或反射的情況下對字串進行文字化和清理?
- 或者有什么方法可以在沒有
inline
and的情況下訪問反射方法(using Quotes)
- 或者如果我提出的解決方案是唯一的方法 - 為什么在類路徑中找不到它,即使匯入似乎有效?
(也對指向教學 Scala 3 宏的優秀視頻或課程的鏈接感興趣。我渴望了解更多資訊,并對這里的可能性感到非常興奮,特別是因為 Exercism 正在添加“代表”,可以為學生和導師提供反饋和改進建議解決方案,看起來非常適合宏。)
uj5u.com熱心網友回復:
這個 Scala 2 方法似乎可以確保在字串化結果之前可以將 String 強制轉換為文字常量?
不,這只是轉換\n
成\\n
等的一種奇特方式。
Scala:如何獲得字串的轉義表示?
你的 Scala 3 宏現在做錯了。從那里嘗試Sim?o Martins的答案
import scala.quoted.*
inline def escape(inline raw: String): String = ${escapeImpl('{raw})}
def escapeImpl(raw: Expr[String])(using Quotes): Expr[String] =
import quotes.reflect.*
Literal(StringConstant(raw.show)).asExprOf[String]
我想 Scala 3 宏現在有點過分了。只需嘗試從那里使用不同的實作來逃避,例如0__的
def escape (s: String): String = "\"" escape0(s) "\""
def escape0(s: String): String = s.flatMap(escapedChar)
def escapedChar(ch: Char): String = ch match {
case '\b' => "\\b"
case '\t' => "\\t"
case '\n' => "\\n"
case '\f' => "\\f"
case '\r' => "\\r"
case '"' => "\\\""
case '\'' => "\\\'"
case '\\' => "\\\\"
case _ => if (ch.isControl) "\\0" Integer.toOctalString(ch.toInt)
else String.valueOf(ch)
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/508586.html