有没有一种惯用的方法来避免长的 Clojure 字符串文字?

Posted

技术标签:

【中文标题】有没有一种惯用的方法来避免长的 Clojure 字符串文字?【英文标题】:Is there an idiomatic way to avoid long Clojure string literals? 【发布时间】:2014-02-01 15:23:26 【问题描述】:

各种 Clojure 样式指南建议避免超过 80 个字符的行。我想知道是否有一种惯用的方法来避免长 String 文字。

虽然现在宽屏很常见,但我仍然同意应该避免排长队。

这里有一些例子(我很想学习第一个):

;; break the String literal with `str`
(println (str
    "The quick brown fox "
    "jumps over the lazy dog"))

;; break the String literal with `join`
(println (join " " [
    "The quick brown fox"
    "jumps over the lazy dog"]))

我知道 Clojure 支持多行 String 文字,但使用这种方法会导致换行符被解释的不良影响,例如使用repl:

user=> (println "The quick brown fox
  #_=>   jumps over the lazy dog")
The quick brown fox
  jumps over the lazy dog

【问题讨论】:

@Chiron:“有没有一种惯用的方法来避免长字符串文字?”是不是真的有问题?真的吗?我的初等教育都是谎言吗? 【参考方案1】:

您可能应该将字符串存储在外部文本文件中,并从您的代码中读取该文件。如果您仍然觉得需要将字符串存储在代码中,请继续使用str

编辑:

根据要求,我将演示如何在编译时读取长字符串。

(defmacro compile-time-slurp [file]
  (slurp file))

像这样使用它:

(def long-string (compile-time-slurp "longString.txt"))

您可以发明类似的宏来处理 Java 属性文件、XML/JSON 配置、SQL 查询、html 或您需要的任何其他内容。

【讨论】:

您可能大部分时间都不应该将字符串放在文本文件中,除非我们谈论的是非常大的文本。它增加了运营成本、性能成本和代码复杂性。正确答案是使用 (str)。 这是 Clojure。 (slurp "myBigString.txt") 不会增加代码的复杂性(并且不如字符串内换行符复杂)。如果文件 IO 的性能有问题,那么该命令可以在编译时通过宏运行。 它引入了您现在需要考虑的不必要的可能故障,这是更高的代码复杂性。您是否认真建议人们在单个文本文件中放置超过 80 个字符的字符串?无副作用函数的整个想法发生了什么变化?仅当文本真正很大、或由外部提供、或动态生成且需要持久化时才将文本放入文件中。 作为第二个说明,你不需要在 Clojure 中的字符串换行符,字符串文字可以跨越多行,并将换行符保留为字符串的一部分。 字符串需要易于开发人员编辑。对于多行字符串,我自己的经验是,在文本文件中编辑它们比在源代码中编辑它们要容易得多。让代码读取文件所增加的复杂性是值得的,因为可以轻松地将文本编辑为单独的文件。【参考方案2】:

我发现使用str 创建字符串并使用诸如\newline\tab 之类的字符文字而不是“\n”来破坏它们很方便。 我很少以这种方式违反 80 列规则。

【讨论】:

【参考方案3】:

我所知道的最惯用的方法如下:

1) 使用 (str) 将字符串拆分为多行。

(str "User " (:user context)
     " is now logged in.")

这可能是最惯用的用法。我已经在多个库和项目中看到了这一点。它很快,因为 (str) 在后台使用了 StringBuilder。它还允许您透明地混合代码,就像我在示例中所做的那样。

2) 在有意义的情况下,允许字符串自行突破 80 个字符的限制。

(format
  "User %s is now logged in."
  (:user context))

基本上,打破字符串的 80 个字符限制是可以的。当您使用代码时,您可能不太关心读取字符串,并且在特殊情况下,您需要水平滚动。

我在此处将字符串包装为(格式),以便能够注入与我之前的示例类似的代码。你不需要。


不太惯用的方法是:

3) 将您的字符串放入文件中并从那里加载它们。

(slurp "/path/to/userLoggedIn.txt")

有一个文件:/path/to/userLoggedIn.txt 包含:

User logged in.

我不建议这样做,因为:

它引入了 IO 副作用 它可能会失败,比如路径错误、资源丢失或损坏、磁盘错误等。 它会影响性能,磁盘读取速度很慢。 如果您也需要,也很难从代码中注入内容。

我会说只有当您的文字真的很大时才这样做。或者,如果字符串的内容需要由非开发人员更改。或者如果内容是从外部获取的。

4) 有一个命名空间,您可以在其中定义所有字符串,然后从那里加载它们。

(ns msgs)
(defn logged-in-msg [user]
  (format
"User %s is now logged in."
    user))

然后你像这样使用它:

(msgs/logged-in-msg (:user context))

比起#3,我更喜欢这个。您仍然需要允许在此处使用 #2,在这里可以让字符串突破 80 个字符的限制。事实上,这里你把字符串自己放在一行上,所以它们很容易格式化。如果您使用 checkstyle 之类的代码分析,则可以将此文件从规则中排除。它也不会受到#3 的问题的影响。


如果您使用 #3 或 #4,您的字符串可能有一个特殊用例,例如国际化或让业务编辑它们等。在这些情况下,您可能会更好地构建更强大的解决方案,这可以从上述方法中得到启发,或者使用专门针对这些用例的库。

【讨论】:

以上是关于有没有一种惯用的方法来避免长的 Clojure 字符串文字?的主要内容,如果未能解决你的问题,请参考以下文章

“foo = bar || baz”的惯用 Clojure 是啥?

Clojure - 1 个函数的 2 个版本。哪个更惯用?

从clojure中的普通lisp替换(null x)函数的惯用方法

生成和管理后台线程的惯用 Clojure 方式

在 Clojure 中添加向量的惯用方法是啥?

什么是惯用的clojure:使用