字符串 escaped/encoded 的类型不同

Types for strings escaped/encoded differently

最近我正在处理 escaping/encoding 问题。我有一堆接收和 return Strings encoded/escaped 不同的 API。为了收拾残局,我想引入新类型 XmlEscapedStringHtmlEscapedStringUrlEncodedString 等,并使用它们代替 Strings.

问题是编译器无法检查 encoding/escaping,我会遇到运行时错误。

我还可以提供 "conversion" 函数,需要时 escape/encode 输入。有道理吗?

编译器可以强制您通过 encoding/decoding 函数传递类型;这应该足够了,前提是你在边界处做对了(如果你有一个正确编码的 XmlEscapedString 并将其转换为 UrlEncodedString,结果总是会被正确编码,不是吗?)。您可以使用最初检查转义的构造函数或转换方法,尽管您可能会为此付出性能损失。

(理论上,可以使用类型级编程在编译时检查字符串的转义,但这将非常困难,而且无论如何只能对文字起作用,当听起来问题是 String来自其他 API)。

我自己的妥协立场可能是使用标记类型(使用 Scalaz 标记)并让从未标记字符串到标记字符串的转换执行检查,即:

import scalaz._, Scalaz._

sealed trait XmlEscaped

def xmlEscape(rawString: String): String @@ XmlEscaped = {
  //perform escaping, guaranteed to return a correctly-escaped String
  Tag[String, XmlEscaped](escapedString)
}
def castToXmlEscaped(escapedStringFromJavaApi: String) = {
  require(...) //confirm that string is properly escaped
  Tag[String, XmlEscaped](escapedStringFromJavaApi)
}

def someMethodThatRequiresAnEscapedString(string: String @@ XmlEscaped)

然后我们使用 castToXmlEscaped 来代替 Strings 已经被认为是 XML-escaped,所以我们在那里检查,但我们只需要检查一次;其余时间我们将它作为 String @@ XmlEscaped 传递,编译器将强制我们永远不会将非转义字符串传递给需要一个的方法。