2024 年 Clojure 调查中分享您的看法!

欢迎!有关如何使用本网站的更多信息,请参阅关于页面。

+8
语法和读取器
编辑

问题

在我(Clojure 代码中)这里和那里包含一些 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 JEPs关于它的动机中得到启发:[https://openjdk.java.net/jeps/355](https://openjdk.java.net/jeps/355)和[https://openjdk.java.net/jeps/326](https://openjdk.java.net/jeps/326)
如果您搜索“原始字符串”、“字符串字面量”、“here doc”、“多行注释”等,Clojure和Clojure-dev google group邮件列表上有许多关于此的讨论。

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

我认为我应该将“拒绝”改为“缺乏兴趣”;我认为Rich通常认为这类东西具有许多细微的复杂性(尤其是对于工具),但相对的收益却较少。
by
不采用三引号方法的论点是:这已经是合法的Clojure代码。

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

它并不表示你所希望的意思,但今天它是有效的,尽管我怀疑任何真正的代码会这样做)
by
好吧,我承认只是搜索了谷歌,并没有特别查看邮件列表 :p。

我还没有想到doc-strings作为用例,但这也是一个很好的用例。

关于这可能引入的工具复杂性的观点很好。解析heredoc或类似的内容可能会更困难。

此外,如果你看看Ruby、Perl和Python,你会发现似乎没有人能就正确的方式达成一致,而且三者最终都支持多种方式。

谈到这并不值得努力去解决的问题。实际上,工具也可以解决这问题。这可能不是用于doc-string用例,而是用于我的代码片段。我知道在IntelliJ中有一个模式,它会为你打开另一个用于自由输入的缓冲区,并且它会自动地对你在字符串内部输入的内容进行Java转义。也许我会在Emacs上也做类似的事情。
by
@sean 好的发现。无论哪种解决方案,我都会倾向于使用reader标签,比如#s """ """之类的。这将解决这个问题。
只是提醒一下,Java 15 也引入了这一特性(我知道这是一个仅限编译器的功能,因此 Clojure 实现与之无关),但也许解决方案空间增长了一年。

只是提醒一下,“原始字符串”,即不需要过多引号的字符串,与读取宏一起,允许实现许多很酷的功能,但目前这些功能过于繁琐,以至于没有人愿意去尝试。
+1

从现状的角度看,-- 把 XML 和 HTML 当作文本一直是让非 Clojure 用户体验到糟糕问题的根源,包括输出格式不正确、注入攻击、糟糕的转换,以及很难评估正确性的代码!

Clojure 的一部分良好声誉源于其在数据(而不是字符串)上建立的传统。“Hiccup”和“clojure.xml”传统已证明在处理 HTML 和 XML 时非常有效,而且在(我所经验到的)执行时非常便宜,因此它们证明了避免在代码中放置数据块的好处。如果您确实有数据块开头,您可以使用 Enlive 等 earliest possible opportunity 进行解析,并以数据结构的形式完成处理。

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

总的来说,我倾向于认为 Clojure 没有满足嵌入和调整代码中的 HTML 和 XML 字面量的需求是明智的(我们也很幸运)。一开始这似乎像是一个缺失的功能,但它的缺失为 Clojure 代码的可靠性提供了巨大的好处。

非常好的观点。对于 HTML 和 XML,我同意。我的驱动力来自于执行服务器端渲染并将一些 JavaScript 嵌入我的 Hiccup 中。

我实际上怀疑 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 JEP的开发方式实验Clojure功能 - 拥有预览版本来发现和完善,直到最终确定并添加到核心中?[https://openjdk.java.net/jeps/326](https://openjdk.java.net/jeps/326)。

我对Clojure相当陌生,对它的语言和全部历史及传统不太熟悉。我喜欢挑战传统,因为世界在变化。使得我们做事的理由可能现在已不再成立。

Clojure没有类似Java JEPs的流程。如果没有Rich Hickey对某种特性的兴趣,那么他将不会将其包含在官方Clojure版本中。

世界上任何人都可以为Clojure源代码创建自己的本地修改并使用它。据我所知,有些组织运行自己的Clojure版本用于内部使用。

为您的本地Clojure副本添加这样的特性将非常简单。但这不会帮助在分布式Clojure程序中使用该特性,因为没有使用官方Clojure版本的人能够编译和运行使用新特性的源代码。
我也想在Clojure中有文本块。
我的用例是将其他编程语言,如Python嵌入。

“文本块”是这类要求之一,如果不是的话,引号问题会非常令人烦恼。
...