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

欢迎!请查看 关于 页面以获取有关此页面如何工作的更多信息。

+8
语法和读取器
编辑

问题

在这里和那里不得不包括一些 JavaScript、XML 和 HTML 在我的 Clojure 代码中,这可能相当烦恼且容易出错,需要转义引号。这同样适用于脚本编写和运行 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 JEPs关于这方面的启发:[JEP 355](https://openjdk.java.net/jeps/355)和[JEP 326](https://openjdk.java.net/jeps/326)
如果您搜索“原始字符串”、“文法”、“这里文档”、“多行注释”等,在Clojure和Clojure-dev谷歌组邮件列表上有很多讨论。

旧设计页面:https://archive.clojure.org/design-wiki/display/design/Alternate%2Bstring%2Bquote%2Bsyntaxes.html

我认为我应当将“decline”修改为“缺乏兴趣”;我认为Rich通常发现这类事情有很多微妙复杂之处(特别是对于工具)而且收益相对较低。
不使用三引号方法的一个观点是,这已经是合法的Clojure。

user=> (println """
这已经是有效的Clojure
""")
 
这已经是有效的Clojure
 
nil
user=>

(这不符合你的期望,但它在今天仍是有效的,尽管我怀疑任何真正的代码都会这样做)
好吧,我承认只搜索了谷歌,而不是特別查找邮件列表 :p。

我还没有想过将文档字符串作为用例,但这同样是个好例子。

关于这可能引入的工具复杂性,这确实是一个很好的观点。解析heredoc或类似的东西可能更困难。

而且,如果你看看Ruby、Perl和Python,你会发现似乎没有人能就如何做这件事达成一致,这三者最终都支持了多种方式。

说到对工具价值不大。事实上,工具也可以解决这个问题。虽然不是为了文档字符串用例,但为了我的代码片段用例。我知道在IntelliJ中,有一个模式会在另一个缓冲区为你打开供自由输入,它会对你输入字符串内的内容自动提供Java转义。也许我也会为Emacs开发类似的功能。
@sean 很好的捕捉。无论解决方案是什么,我会倾向于使用reader标签。例如,使用#s """ """ 或类似的东西。这将解决问题。
只是想提一下,Java 15 也引入了这一点(我知道它只是一种编译器特性,所以 Clojure 实现与此无关),但也许解决方案空间只是略微增长了一点。

只是想提一下,“原始字符串”,即需要较少引号的字符串,以及阅读宏一起,可以让许多现阶段令人烦恼的功能变得酷炫起来。
+1

从现状的积极角度来看,—— 将 XML 和 HTML 作为文本处理,一直以来都使非 Clojurists 遭受糟糕的麻烦,包括输出格式不正确、注入、笨拙的转换以及难以评估正确性的代码!

Clojure 的一些良好声誉要归功于根植于数据(而不是字符串)的传统。“Hiccup”和“clojure.xml”传统在处理 HTML 和 XML 方面非常有效,而且(在我的非量化经验中)在运行时出奇的便宜,这使得避免在代码中放置数据块成为一件神奇的好处。如果你确实需要数据块,你可以尽早用 Enlive 等工具解析它们,并按数据结构完成处理。

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

总的来说,我认为 Clojure 做得明智(而且我们很幸运)避免了将 HTML 和 XML 字面量嵌入代码并调整它们的需求。一开始这可能看起来像是一个缺少的功能,但它的缺失对 Clojure 代码的可靠性却是一个巨大的好处。

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

我其实曾想过 CLJS 是否可以以这种方式嵌入,但我觉得不行。尽管如此,如果它能,那将会非常棒。
+1

你好,

我也支持为Clojure添加此功能。我认为一个优秀的用例是支持如样式化组件等功能(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 JEP的开发方式来实验Clojure的功能—拥有预览版本以探索和改进,直到最终确定并添加到核心?(https://openjdk.java.net/jeps/326)。

我对Clojure相当陌生,我对语言以及它的历史和传统也不太熟悉。我非常喜欢挑战传统,因为世界正在变化。过去让我们这样做的原因可能现在不再适用。

Clojure没有类似于Java JEPs的过程。如果Rich Hickey对某个特性不感兴趣,他就不会将其作为Clojure官方版本的一部分。

世界上的任何人都可以为自己的Clojure源代码创建本地更改并使用它。我听说有组织运行他们自己的Clojure补丁版本用于内部使用。

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

“文本块”对此是个要求,如果不是引号问题真的很烦人。
...