2024 年 Clojure 状态调查!中分享您的想法。

欢迎!请参阅关于页面了解更多有关此功能的详细信息。

+8
语法和读取器
编辑

问题

在此处和那里需要包含一些 JavaScript、XML 和 HTML,因此必须转义引号可能会导致相当麻烦且容易出错。这在编写脚本和运行 shell 命令时也是如此,您可能会遇到复杂的转义场景。

解决方案

添加一个字符串字面量,它可以根据需要包含任何类型的字符串,而不需要转义。

建议

文本块

某些其他语言提供一种称为文本块的功能,您可以编写三引号或更多引号之间的字符串,然后所有字符都允许存在

(println """
         This " is allowed,
         and no need to escape it.
         """

文本块通常包含一些附加功能,例如,字符串中第一个和最后一个换行符不属于字符串本身。并且在源代码中三引号的位置区分了引号中的行开始。因此,上面的代码打印为

This " is allowed,
and no need to escape it.

而不是

         This " is allowed,
         and no need to escape it.

尽管文本块在视觉效果上很整洁,因为它们在源代码中具有很好的对齐,但它们依赖于空白,而 Clojure 一直是一种不依赖于空白(即空白无关)的语言,这意味着空白没有意义。我认为最好保持这种方式。因此,以下是下两个建议。

原始字符串

有时不带“块”功能的文本块称为原始字符串字面量

(println """This " is allowed,
and no need to escape it.
Also support multi-line, but
not the "block" style of text blocks.""")

因此

(println """
         This " is allowed,
         and no need to escape it.
         """

打印

         This " is allowed,
         and no need to escape it.

与文本块不同。

如果您需要一个三引号,只需将分隔符改为四引号即可

""""This """ is now allowed as well.""""

原始字符串的问题在于,如果您使用双引号作为分隔符

""This is a raw " string!""

但希望在开始或结束处有单引号

"""{{hello}}"""

我想得到字符串:"{{hello}}",而不是 {{hello}},但原始字符串无法区分这两个,因为它现在认为这是一个三引号分隔符。

一个解决方案是允许仅在大括号的开头或结尾处使用转义引号

""\"{{hello}}\"""

而不是在中间

""\"{{he\llo}}\"""

这是字符串:"{{he\llo}}"

因此,转义字符 \ 可以出现在除紧跟引号的开始之外的所有地方,以及紧跟引号的结束处。

我认为这还不够完美。存在太多规则,仍然还有一些需要转义的情况。

未转义字符串(我最喜欢)

这里的想法是允许任何字符串用作分隔符。因此,对于任何我们想在Clojure代码内部嵌套的可能字符串,我们总能找到一个不包含它的字符串来用作分隔符。

假设添加了#text读取宏。它期望以下形式是一个普通字符串,它告诉它以下形式的分隔符。

(println #text "|" |"{{hello}}"|)

将打印

"{{hello}}"

#text的第一个参数告诉它以下原始字符串应该用哪个分隔符。这样,你绝对不需要在原始字符串内部使用转义序列。对于任何给定的字符串,你都可以找到一个不包含它的分隔字符串来正确处理它。

关于这种方法的一个疯狂的想法,我只是随便提一下,如果你使用足够随机的字符串作为分隔符,这可能是一种奇特的防止注入方法。

(println #text "xIBgdSl4TCCOIdqdMu9G" xIBgdSl4TCCOIdqdMu9G
Can't nobody guess the delimiter to escape the string context :p
xIBgdSl4TCCOIdqdMu9G)

谢谢

3 个答案

+1

这已经在Clojure的生命周期中多次被要求并被拒绝,我认为这里没有新的论点。

哼,我确实先尝试搜索了一下。找不到任何东西。我受到即将到来的Java JEP(Java Epidemiology Project,Java普及项目)关于这一点的启发:[https://openjdk.java.net/jeps/355](https://openjdk.java.net/jeps/355)和[https://openjdk.java.net/jeps/326](https://openjdk.java.net/jeps/326)。
在 Clojure 和 Clojure-dev 的 Google 群组邮件列表上有很多关于“raw string”、“string literal”、“heredoc”、“多行注释”等内容的讨论。

旧设计页面:[点击查看](https://archive.clojure.org/design-wiki/display/design/Alternate%2Bstring%2Bquote%2Bsyntaxes.html)

我认为我应该将“拒绝”改为“缺乏兴趣”;我认为一般来说,Rich 认为这类事情有很多微妙复杂性(尤其是对于工具而言),而收益却相对较低。
不使用三引号方法的理由之一是,这已经是合法的 Clojure 代码。

user=> (println """
这已经是合法的 Clojure 代码
""")
 
这已经是合法的 Clojure 代码
 
nil
user=>

这可能不是你想要的意思,但在当前,即使我怀疑没有真正的代码这样做,它也是有效的)
好吧,我承认我只搜索了谷歌,而没有专门查看邮件列表:p。

我没有想过文档字符串会是一个用例,但这也是一个很好的用例。

这个提出的问题是,这可能会引入工具复杂性。解析 heredoc 或类似的内容可能更困难。

此外,如果你看看 Ruby、Perl、Python,你就会看到似乎没有人能够达成一致,并且这三个都支持了多种方法。

说到不值得一试的工具。这实际上也是工具可以解决的问题。虽然不是针对文档字符串的使用场景,但对我来说,我 snippet 用例也是如此。我知道在 IntelliJ 中,有一个模式可以在另一个缓冲区中为你打开一个打开的区域,你可以自由地在那里键入,而它会自动将你输入的字符串中的 Java 转义。也许我也会为 Emacs 开发类似的功能。
@sean 你的提醒很好。无论是什么解决方案,我个人倾向于使用它来使用 reader tag。所以 #s """ """ 或类似的方式。这将解决这个问题。
只是简单提一下,Java 15 也引入了这个特性(我知道这是一个仅限于编译器的功能,所以 Clojure 实现与此无关),但也许解决方案空间又扩展了一点。

只是提一下,“原始字符串”,即需要较少引号的字符串,加上读取宏,可以实现很多很酷的功能,但当前这些功能足够烦人,以至于没有人愿意为之烦恼。
+1

从现状的角度看,将 XML 和 HTML 视为文本始终会使非 Clojure 用户陷入可怕的麻烦,包括输出格式错误、注入、笨拙的转换,以及难以评估正确性的代码!

Clojure 的良好声誉部分得益于数据(而非字符串)上的约定。"Hiccup" 和 "clojure.xml" 约定对 HTML 和 XML 非常有效,而且(在我的非量化经验中)运行时非常便宜,这证明了不将数据块植根于代码的好处。如果您一开始就有数据块,可以在数据结构上尽快使用 Enlive 等工具进行分析,并完成处理。

嗯,JavaScript 可能有点牵强。最好是从资源中获取它?如果您在 ClojureScript 中编码,可以使用宏在编译时从与 cljs 文件相同的类路径中提取资源。

总体而言,我倾向于认为 Clojure 没有嵌入和调整代码中的 HTML 和 XML 字面量的诱惑是明智的(并且我们非常幸运)。一开始可能会觉得这是一个缺少的功能,但它的缺失为 Clojure 代码的可靠性带来了好处。

非常好的观点。而且对于 HTML 和 XML,我同意。我的动力来自于服务器端渲染,需要在 Hiccup 中嵌入一些 JavaScript。

我实际上曾想过 CLJS 是否可以以这种方式嵌入,但我认为不行。尽管如此,如果它能那样做,那就会很好。
+1

重启

你好,

我也想支持将此功能添加到clojure。在我看来,支持类似styled components的东西是个不错的用例https://styled-components.npmjs.net.cn/

const Button = styled.a`
  /* This renders the buttons above... Edit me! */
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;

  /* The GitHub button is a primary button
   * edit this to target it specifically! */
  ${props => props.primary && css`
    background: white;
    color: palevioletred;
  `}
`

上述代码的主要优点在于大部分是纯CSS - 不需要转换为Clojure。

在clojure中添加原始字符串/文本块是否有问题?是的。
让我们讨论一下这个问题,看看我们能走多远。

是否有方法以类似Java JEPs现在开发的方式在clojure中尝试特性 - 拥有预览版本以发现和改进,直到最终确定并添加到核心?https://openjdk.java.net/jeps/326

我相当新加入Clojure,对语言以及它的历史和传统不是很熟悉。我喜欢挑战传统,因为世界正在变化。过去让我们做事的原因可能现在不再适用。

对于Clojure,没有类似于Java JEPs的过程。如果Rich Hickey对某个功能不感兴趣,那么他不会将其纳入官方Clojure版本。

世界上任何人都可以创建自己的本地Clojure源代码更改并使用它们,如果他们愿意。我听说有一些组织运行了为自己用途打补丁的Clojure版本。

为你的本地Clojure副本添加此类功能将非常简单。但这并不帮助在分布式Clojure程序中使用该功能,因为使用官方Clojure版本的人将无法使用新功能来编译和运行源代码。
我也希望在Clojure中使用文本块。
我的使用场景是嵌入其他编程语言,比如Python。

“文本块”是该功能的一个必备条件,否则引号问题过于烦人。
...