在 Scala 中使用符号的实际例子?
Posted
技术标签:
【中文标题】在 Scala 中使用符号的实际例子?【英文标题】:Practical examples of using symbols in Scala? 【发布时间】:2010-11-22 09:46:24 【问题描述】:Scala 有符号 - 名称以单引号 ' 开头,是一种字符串常量。
我知道 Ruby 中的符号(它们以冒号开头)。在 Ruby 中,它们用于一些元编程任务,例如为成员变量生成 getter 和 setter(例如 attr_reader :name
为 name
生成 getter)。
我还没有看到在 Scala 代码中大量使用符号。 Scala 中符号的实际用途是什么?
【问题讨论】:
【参考方案1】:我想当你想引用一个不是代码中现有标识符的事物的名称时,你会使用它们。 Scala 书中给出了引用数据库列名称的示例 - 它不是任意字符串,它实际上是事物的名称。
不过,这有点脆弱,我并不完全相信。
【讨论】:
【参考方案2】:根据 Scala 书,Symbols 是实习的:“如果你写两次相同的符号,两个表达式将引用完全相同的Symbol
对象。”
相比之下,String
s 仅在它们以文字形式出现时才会被实习(至少在 Java 中它们是,但对 Scala 并不完全确定)。所以我想如果你对String
s 进行大量序列化,然后将它们放入集合中,你可能会使用符号来代替并节省一些内存。
但我同意 skaffman 的观点,我并不完全相信它们的用途。
(在 Ruby 中,Symbol
s 除了您给出的元编程示例外,通常用作 Hash
es 中的键。在 Ruby 中,这很有用,因为在那里,String
s 永远不会被实习:每个String
分配新内存。正如我所提到的,在 Scala 中它可能很有用,如果你将它与大量(反)序列化结合起来,那么 Java String
s 也不会被实习。)
【讨论】:
但是如果你使用字符串文字而不是符号文字,这是问题的重点,那么两者都会被实习。 没错,这就是序列化很重要的原因。它会为相同的字符串提供不同的对象,而 Symbols(据说)不会。此外,问题没有明确指定符号文字。如果它是你想要的文字,我的回答确实并不适用。我想,这会使符号更加脆弱:)。 Symbols 的自动实习还意味着 Symbols 的 equals() 可以实现为引用相等检查,因此比较可以非常快(而不是比较两个字符串的每个字符)。这意味着它们在许多用途上比字符串更有效,例如当用作 Map 中的键时? 注意:你可以像在 Java 中使用 "asdf".intern() 从字符串中获取实习生。 反序列化真的很重要。符号反序列化呢?保留身份似乎很重要,但您如何做到这一点?没有任何内容讨论 Symbold 序列化,尽管它至关重要,IMO。【参考方案3】:我相信符号之间的比较更快。如果您使用过 Erlang,则在传递消息时会使用大量符号,并且您想要便宜、快速、跨机器边界运行良好的东西。我不确定远程演员在 Scala 和 IIRC 中处于什么状态,它们相当狡猾,但是将来当它们到位时,符号很可能会非常有用,就像它们在 Erlang 中一样。还有案例类,一些好处并不那么明显,但同样,符号仍然更便宜。
【讨论】:
【参考方案4】:符号真的适合 Scala 吗?
在美妙的 Lisp 领域,代码被表示为表示自身的文字对象(字符串、数字等)和符号的嵌套列表,符号用作类、函数和变量等事物的标识符。由于 Lisp 代码具有非常简单的结构,Lisp 允许程序员操作它(在编译时和运行时)。显然,在这样做的时候,程序员不可避免地会遇到符号作为数据对象。
所以符号在任何情况下都是(并且必须是)Lisp 中的对象,那么为什么不将它们用作哈希表键或枚举呢?这是做事的自然方式,它使语言保持简单,因为您不必定义特殊的枚举类型。
总而言之,符号自然地用于代码操作、枚举和键控。但是 Java 人默认不使用身份作为哈希键之间的等价关系(您的传统 Lisp 就是这样做的),因此他们可以只使用字符串作为键。枚举类型在 Scala 中单独定义。最后,该语言根本不支持将代码作为数据。
所以不,我的印象是符号不属于 Scala 语言。也就是说,我将密切关注对这个问题的答复。他们可能仍然展示了在 Scala 中对符号的真正使用,这是我现在想不到的。
(附录: 根据 Lisp 方言,Lisp 符号也可能是命名空间限定的,这当然是在操作代码时非常有用的功能,而字符串则不具备这样的功能有。)
【讨论】:
您仍然希望在字符串上使用符号来键入哈希值,或者不这样做,因为它们更便宜并且更容易重构,强调后者。符号(如果有的话)促进代码和数据的分离,这在 Scala 中很受追捧,正如您清楚地说的那样,这不是一些在代码库中碰巧命名相同的魔术字符串,但它实际上是代码。 @Saem 你对代码和数据是正确的,但是,唉,在这方面,case 对象几乎每次都会击败符号。请参阅我对有关 Scala 中类型安全枚举的问题的回答。【参考方案5】:我猜 Scala 添加它们是因为函数式语言使用它们。
但是,他们忘记了添加通过符号引用标识符的能力,这是他们存在的中心点。 Scala 2.8 中有一个实验性功能可以提供其中的一些功能。我将完整引用 API 文档的相关部分:
@experimental
object Invocation
extends AnyRef
一种更方便的反射调用语法。 示例用法:
class Obj private def foo(x: Int, y: String): Long = x + y.length
您可以通过以下两种方式之一进行反思:
import scala.reflect.Invocation._
(new Obj) o 'foo(5, "abc") // The 'o' method returns Any
val x: Long = (new Obj) oo 'foo(5, "abc") // The 'oo' method casts to expected type.
如果您调用oo
方法并且没有给类型推断器足够的帮助,它很可能会推断Nothing
,这将导致ClassCastException
。
作者 保罗·菲利普斯
【讨论】:
【参考方案6】:在网上搜索了一下,似乎 Scala(类似语言)中的符号(符号文字)与字符串相比是语义问题,因此甚至可能是编译器意识问题。
'String' 是一种数据类型,由一系列字符组成。您可以对字符串进行操作,从而对它们进行操作。字符串在语义上可以是任何文本数据,从文件名到要在屏幕上打印的消息、CSV 文件中的一行,等等。
对于编译器 - 因此 IDE - 字符串是数据类型 String 的值,就像数字(数字序列)是数据类型的值,比如:Integer。 “foo”和“bar”在程序层面没有区别。
OTOH 符号是标识符,即在语义上标识程序中的项目。 在这个问题上,它们就像类名、方法名或属性名。 但是,虽然类名标识了类-即声明类的结构和行为的一组属性 - 以及方法名称标识方法 - 即参数和语句-,符号名称标识符号-即本身,仅此而已-。
所以编译器可以明确区分符号'foo 和'bar,就像他区分类Foo 和Bar。作为编译器符号表的一部分,您可以在 IDE 中应用相同的机制,例如搜索 'foo 的用法(即对该符号的引用),就像您搜索类 Foo 的用法一样。
相比之下,搜索字符串“foo”需要不同的方法,例如全文扫描。它遵循与在程序代码中搜索所有出现的 4711 相同的语义。
我是这么理解的,如果我错了,有人可以纠正我。
【讨论】:
【参考方案7】:我可以举出一种在 Scala 中真正使用符号的情况。 Play 2.2 使用 anorm 来访问数据库。 下面是简单的添加实体方法的代码示例:
def add(e:Entity): Option[Long] =
DB.withConnection implicit conn =>
SQL("insert into ENTITY(name, description) values(name, description)").on('name -> e.name, 'description -> e.description).executeInsert()
所以你可以在.on(bla bla bla)中看到符号的用法 使用字符串文字代替符号也是绝对有效的,有些人正在这样做,但是在异常源代码中,相应的方法签名确实使用符号参数类型。
【讨论】:
【参考方案8】:如前所述,符号从其他(更多)函数式语言中继承。其他人没有提到的是,它们不仅填补了符号的作用,而且它们也是最接近关键字的等价物(可能减去性能优势)。在我看来,它们作为关键字更有用,意味着明确的标识符。
下面我将包含来自Clojure docs 的关键字和符号的法庭描述。
符号
符号是通常用来指代其他事物的标识符。它们可以在程序形式中用于引用函数参数、let 绑定、类名和全局变量。它们有名称和可选的命名空间,两者都是字符串。符号可以有元数据(参见 with-meta)。
关键词
关键字是对自身求值的符号标识符。它们提供了非常快速的相等性测试。像符号一样,它们有名称和可选的命名空间,两者都是字符串。前导 ':' 不是命名空间或名称的一部分。
Scala 符号不如某些语言中的符号强大。因此,它们也没有那么有用。但是,我不明白为什么它们不能提供与关键字相同的元编程和性能优势。至少,它们可以使您的代码更易于阅读。
【讨论】:
以上是关于在 Scala 中使用符号的实际例子?的主要内容,如果未能解决你的问题,请参考以下文章