【问题标题】:Why does Scala implicitly convert Char to Int?为什么 Scala 将 Char 隐式转换为 Int?
【发布时间】:2010-12-01 16:43:07
【问题描述】:

查看自动导入的scala的Predef对象,发现following gem

implicit def char2int(x : Char) : Int

这导致一些肮脏的错误潜入我的代码(在Map[Char,Int] 中使用_1 而不是_2)。我真的不明白,我为什么要隐式Char 转换为Int。拥有Char 类型(这只是一个数字)的整个想法是,我不会将它用作数字(反之亦然)。

我使用 scala 的类型系统是为了避免出现这样的错误!

我想到的唯一(坏)借口是与 Java 的可怕行为兼容。

更新:到目前为止给出的两个答案给出的主要原因是,隐式转换是为了支持Char 类型的有序操作。例如'c'+1 会生成d。如果这是你想要的,你应该这样做

class Char ...
    ...
    def +(x:Int) = (this.toInt+x).toChar
    def <(x:Char) = this.toInt < x.toInt

您可以根据自己的喜好添加和比较字符。 Char 是唯一的 16 位数字这一事实仅意味着我们需要一个新的 Word(或 Short)类型。

【问题讨论】:

  • 我也被这个咬过,所以你不是一个人在想。

标签: scala types


【解决方案1】:

好吧,如果您考虑如何表示 Char,则 Char 是一个无符号的 16 位字段,范围从 (0 到 2^16 - 1)。这可以适合Int(32 位有符号,范围从 -2^31 到 2^31 - 1)中没有溢出。

Scala 的一些基本类型,按照它们的表示长度(以位为单位):

  • Byte(8)
  • Char (16)
  • Int (32)
  • Long (64)

Char 外,所有都已签名,并且都可以转换为“低于”它的类型,因为它们永远不会溢出/不足(ByteChar 除外,它不存在)。在Predef 中查看所有这些隐式转换。

这就是我认为存在隐式转换的原因 - 允许存在如下表达式:

def foo(c: Char) { println(c) }
foo('a' + 2) // prints c

另一种解释与您给出的解释类似(Char 只是一个数字......)。对我来说,这很有意义——所有Chars 的集合都包含在所有Ints 的集合中,因此,applying my own guidelines for using implicits 的转换应该是隐式的。

我确实理解您的烦恼,因为我喜欢编译器发出错误信号,就像您刚才举的例子一样。如果 Scala 有办法关闭隐式转换(或关闭特定隐式转换,因为将它们全部关闭可能会造成严重破坏!)

对于您的问题,我看到的唯一解决方案是使用 Map[RichChar, Int] 或类似的东西 - RichChar 被隐式转换为 Int,因为无法链接隐式转换。 EDIT 发现实际上没有RichCharChar 的隐式转换。

def foo(x: Int) = x + 1

import scala.runtime.RichChar

val ch = 'a'
val rch = new RichChar('a')

foo(ch) // compiles fine
// foo(rch) // does not compile

def bar(ch: Char) = println(ch) 

// bar(rch) // oops... does not compile
implicit def rch2char(rch: RichChar): Char = rch.self.asInstanceOf[Char]

bar(rch) // yay!

编辑:实际上,如果您仔细了解 Scala API,Char 确实有一个重载的 + 方法,它接受一个 Int 参数。 Int 也是如此。这可能与底层 JVM 做了类似的事情有关。

还请注意,我给您的示例与允许将Ints 添加到Chars 无关! API 已经允许这样做。更微妙的一点是,当您将Int 添加到Char 时,您会得到一个Int。隐式转换允许将此添加的结果用作Char

还要注意我给出的更理论的答案 - CharInt 的子集!

-- Flaviu Cipcigan

【讨论】:

    【解决方案2】:

    它可能并不完美,但请考虑替代方案......

    这只是一个实施选择。在某一时刻,许多语言确实在 charint 之间做出了很大的区分,但是由于它们总是必须具有转换功能,因此实际上并没有太多阻塞,而 确实 只是一个很大的痛苦.

    没有人真的想回到到处都是chr(n)ord(c) 的日子。想象一下 UTF-8 处理会是多么有趣。

    一旦 C 出现 chars 真的是 ints,它就震撼了,我们甚至在强类型语言中也一直保持这种状态。

    现在,如果您真的想要一个不会自动转换的封装Char,没有什么能阻止您为自己的代码定义一个新类型,比如ElazarChar。我怀疑你会讨厌它。

    【讨论】:

    • 我考虑了替代方案并在更新的问题中提出了一个。
    • 您的观点非常好,但请记住,您提出的实际问题不是 “这是个好主意吗”“这个替代方案怎么样” i>,但 “为什么 Scala...”。我总是试图回答所提出的确切问题,尽管这确实经常给我带来麻烦。有人曾经问过如何浅拷贝一个(不可变的)列表,所以我给出了确切的答案,并因为告诉他复制一个 val 而受到抨击。 :-)
    • 我想问你“你有手表吗?”是个坏主意。如果我想知道时间...
    猜你喜欢
    • 2013-10-05
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 2013-01-26
    • 1970-01-01
    • 2011-03-31
    • 2015-01-20
    相关资源
    最近更新 更多