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

欢迎!请参阅 关于 页面,了解有关此内容的更多信息。

0
打印

user=> (read-string (pr-str {(keyword "key@other") :stuff}))
RuntimeException Map literal must contain an even number of forms  clojure.lang.Util.runtimeException (Util.java:170)


pr-str 输出 "{:key@other :stuff}", 但 read-string 无法正确解析。要么 pr-str 需要转义 @ 符号,要么 read-string 需要正确处理关键字内的符号。

背景:我正在将带有电子邮件地址的映射作为 Storm bolts 的键传递,这些 bolts 需要thrift-serializable形式。使用 pr-str/read-string 组合在这些键上失败,所以我退回到使用 JSON 序列化。

8 答案

0

评论由:stu

'@' 字符不是关键字或符号的有效字符(见 https://clojure.org/reader)。已重新分类为增强请求数据。

0

评论由:stevenruppert

那么为什么 (keyword "keywith@") 不会抛出异常?这与您的声明似乎不一致。

0

评论由:jafingerhut

Cljure一直有一个长期属性,那就是它不会对所有非法操作抛出异常。

0

评论由:stevenruppert

是的,但read-string会这样做。为什么"keyword"函数不能抛出异常呢?与其他关于符号名内命名空间的特殊规则相结合,"keyword"函数实际上应该进行验证。

另一个解决方案是允许一个类似Ruby的:"不允许字符的符号"字面量,但这也会与命名空间的处理方式产生混淆。

https://groups.google.com/forum/?fromgroups=#!topic/clojure/Ct5v9w0yNAE有关这个话题的某些旧讨论。

0

评论由:jafingerhut

免责声明:我不是Clojure/core成员,只是一个对此感兴趣的贡献者,不知道在这里做出了哪些设计决策。

Steven,我认为可能有两点关注:一是进行此类检查会比不进行检查慢,二是实现这些检查意味着如果/当合法符号、关键词、命名空间名称等的规则发生变化时,需要更新它们。

您是否愿意编写严格的版本,例如symbol和keyword函数,并将其添加到contrib库中?并且编写测试套件以尝试击中原则和原则中大量角落案例?我的意思是认真的问题,而不是修辞问题。这将允许那些想要使用这些函数的严格版本的人这么做,同时也可以轻松测量严格和宽松版本之间的性能差异。

0

评论由:stevenruppert

回顾这个问题,问题的根本原因是{pr}函数,尽管它会默认以"print(link: s)的方式打印对象,以便读者可以读取"(link: 0),但这并不总是这样做。因此,最容易的“解决”方法是将其文档字符串更改为警告说,并非所有关键词都可以被读取回来。

deeper problem is that symbol没有reader形式可以表示所有实际可能的关键词(在这种情况下,包含"@"的关键词)。将实际上可能的关键词限制为与reader形式匹配,即编写严格的"keyword"函数,实际上似乎是一个更糟糕的整体解决方案。更好的解决方案可能是以某种方式扩展keyword reader形式,使其能够表达所有可能的关键词,可能是Ruby的:"keyword"语法。此外,该解决方案可以避免需要保持假设的严格keyword/symbol函数与reader操作同步,以及编写针对这些操作的测试用例,等等。

因此,此错误的解决方法在于我们愿意走多远。更改文档字符串是最简单的,但扩展关键字形式将是我认为的“最佳”解决方案。

(链接:0): https://docs.clojure.org/clojure_core/clojure.core/pr

0

评论由:jafingerhut

我昨天偶然发现了 CLJ-17 这个问题。它的讨论线程显示,验证构造关键字和符号内容的话题之前已经出现过。当时,编写了一个补丁,修改了“symbol”和“keyword”函数,以便符号/关键字按照现在的样子构造,但随后使用 clojure.lang.RT/readString 方法双检查字符串参数的可读性。如果 intern 和 readString 方法返回的符号不等于(或者在 readString 抛出异常的情况下),它会抛出异常。

Rich 担心这种运行时开销会太高,并询问是否有人知道更快的做法。Chas Emerick 建议使用类似于 Common Lisp 的 #|符号与空格|语法,以及一些检查,以防引用是多余的。Rich 对引用任意符号的想法持开放态度,但这将是一个与那个不同的票。

我不知道自那时以来有人提出创建一个关于引入任意符号引用的票据,但我可能错过了。这个票据可以成为那样的票,但它的描述需要重大编辑,并且需要在 Clojure 的多个地方修改代码。

0
参考: https://clojure.atlassian.net/browse/CLJ-1033 (由 alex+import 报告)
...