代码之家  ›  专栏  ›  技术社区  ›  Randall Schulz

scala中“弱一致性”的概念是什么?

  •  27
  • Randall Schulz  · 技术社区  · 14 年前

    我最近遇到了术语“弱一致性”(在堆栈溢出用户中) retronym 的答案 How to set up implicit conversion to allow arithmetic between numeric types? )

    这是怎么一回事?

    3 回复  |  直到 11 年前
        1
  •  20
  •   retronym    14 年前

    3.5.3在某些情况下,scala使用了更一般的 一致性关系。弱S型 符合T型,书写S<: W T ,如果S<:t或S和T都是 基元数类型和s先于 按以下顺序排列。

    • 字节& lt; W
    • 字节& lt; W 性格
    • 短小; W int
    • INT< W
    • Long & lt; W 浮标
    • 浮动: W 双重的

    弱最小上界是 关于弱的最小上界 一致性。

    这是在哪里用的?首先,它决定了 if 表达:

    条件表达式的类型 是E2和E3类型的弱最小上界(_§3.5.3)

    在scala 2.7.x中,按类型 AnyVal ,的最小上界 Int Double . 在2.8.x中,它键入 双重的 .

    scala> if (true) 1 else 1d
    res0: Double = 1.0
    

    类似地:

    scala> try { 1 } catch { case _ => 1.0 }
    res2: Double = 1.0
    
    scala> (new {}: Any) match { case 1 => 1; case _ => 1.0 }
    res6: Double = 1.0
    
    scala> def pf[R](pf: PartialFunction[Any, R]): PartialFunction[Any, R] = pf
    pf: [R](pf: PartialFunction[Any,R])PartialFunction[Any,R]
    
    scala> pf { case 1 => 1; case _ => 1d }
    res4: PartialFunction[Any,Double] = <function1>
    

    另一个使用它的地方是类型推断:

    scala> def foo[A](a1: A, a2: A): A = a1
    foo: [A](a1: A,a2: A)A
    
    scala> foo(1, 1d)
    res8: Double = 1.0
    
    scala> def foos[A](as: A*): A = as.head
    foos: [A](as: A*)A
    
    scala> foos(1, 1d)
    res9: Double = 1.0
    

    对于简单的数字加宽:

    数值加宽。如果e有一个原语 弱符合的数字类型 (_§3.5.3)对于预期类型,它是 使用一个扩展到预期类型 的 6.26隐式转换97数字转换方法Toshort、Tochar, Toint、Tolong、Tofloat和Todouble _§12.2.1中定义。所需类型为 基元数字类型字节、短或 char,表达式e是 范围内的整型文字拟合 对于该类型,它将转换为 该类型中的文本相同。

    scala> 1: Double
    res10: Double = 1.0
    

    更新

    正如Daniel所指出的,对于哪些类型的一致性较差,规范是错误的。让我们问问编译器本身:

    scala> :power
    ** Power User mode enabled - BEEP BOOP      **
    ** scala.tools.nsc._ has been imported      **
    ** New vals! Try repl, global, power        **
    ** New cmds! :help to discover them         **
    ** New defs! Type power.<tab> to reveal     **
    
    scala> settings.maxPrintString = 10000
    
    
    scala> import global.definitions._
    import global.definitions._
    
    scala> (for{c1 <- ScalaValueClasses;
          c2 <- ScalaValueClasses
          isNSC = isNumericSubClass(c1, c2)
          if isNSC
      } yield ("isNumericSubClass (%s, %s) = %b" format (c1, c2, isNSC))).mkString("\n")
    
    
    res5: String =
    isNumericSubClass (class Byte, class Byte) = true
    isNumericSubClass (class Byte, class Short) = true
    isNumericSubClass (class Byte, class Int) = true
    isNumericSubClass (class Byte, class Long) = true
    isNumericSubClass (class Byte, class Float) = true
    isNumericSubClass (class Byte, class Double) = true
    isNumericSubClass (class Short, class Short) = true
    isNumericSubClass (class Short, class Int) = true
    isNumericSubClass (class Short, class Long) = true
    isNumericSubClass (class Short, class Float) = true
    isNumericSubClass (class Short, class Double) = true
    isNumericSubClass (class Int, class Int) = true
    isNumericSubClass (class Int, class Long) = true
    isNumericSubClass (class Int, class Float) = true
    isNumericSubClass (class Int, class Double) = true
    isNumericSubClass (class Long, class Long) = true
    isNumericSubClass (class Long, class Float) = true
    isNumericSubClass (class Long, class Double) = true
    isNumericSubClass (class Char, class Int) = true
    isNumericSubClass (class Char, class Long) = true
    isNumericSubClass (class Char, class Char) = true
    isNumericSubClass (class Char, class Float) = true
    isNumericSubClass (class Char, class Double) = true
    isNumericSubClass (class Float, class Float) = true
    isNumericSubClass (class Float, class Double) = true
    isNumericSubClass (class Double, class Double) = true
    
        2
  •  5
  •   Community dbr    7 年前

    完成 Sandor's answer ,2.8中的新功能仍在烘焙(和修复)。

    this thread 埃瑟发现了一个令人讨厌的副作用:

    scala> val a= 10 
    a: Int = 10 
    
    scala> val b= 3 
    b: Int = 3 
    
    scala> if (b!=0) a/b else Double.NaN 
    res0: Double = 3.0 
    
    scala> def div1(a: Int, b: Int) = if (b!=0) a/b else Double.NaN 
    div1: (a: Int,b: Int)Double 
    
    scala> def div2(a: Int, b: Int): Double = if (b!=0) a/b else Double.NaN 
    div2: (a: Int,b: Int)Double 
    
    scala> div1(10,3) 
    res1: Double = 3.0 
    
    scala> div2(10,3) 
    res2: Double = 3.3333333333333335 
    

    似乎很有趣,因为隐式找到的结果类型是 Double 结果是3.0。
    如果明确给出double,则结果为3.33…

    this thread ,Martin Odersky补充道(6月21日):

    您发现了重载解决方案中弱一致性规则的严重意外副作用。
    问题是重载方法的参数需要弱一致,而结果类型需要强一致。

    这有利于 Float => Float 上的加法 Int 超过 Int => Int 方法,如果结果类型为float。
    我试图保守我对弱一致性的更改,因为我只需要看起来绝对必要的弱一致性。
    但现在看来,保守导致了我们所关注的问题!

    还有另一个scala rc版本;)


    确认在 this thread by Martin Odersky (June 22d) :

    因此,到目前为止,将有一个RC7与RC6相比有三个变化:

    1. val x: Double = 10/3 将给予 3.0 不是 3.3333333 -这就是我提到的回归
    2. […]
    3. […]

    就是这样。我们现在的首要任务是尽快推出2.8,同时避免像上面(1)这样的严重倒退。

    时间线:

    • 我们将再等一周以获得关于RC6的反馈。
    • 下周早些时候我们将推出RC7。
      如果没有进一步的问题显示RC7将变成2.8最终10-14天后,它被释放。

    (我相信大约在7月12日左右,但这是我的猜测;)

        3
  •  4
  •   Sandor Murakozi    14 年前

    根据scala lang规范2.8:
    http://www.scala-lang.org/archives/downloads/distrib/files/nightly/pdfs/ScalaReference.pdf

    3.5.3不合格
    在某些情况下,scala使用一种更为性别一致性的关系。弱S型 如果S<:t或S和T都是原始数字,则符合T类型,即S<:W T。 类型和s在下面的顺序中位于t之前。
    字节<:w短
    字节<:w字符
    短<:w int
    英寸长
    长浮动
    浮动<:w双
    弱最小上界是弱一致性的最小上界。

    推荐文章