Scala中"弱一致性"的概念是什么?

Ran*_*ulz 27 scala scala-2.8

我最近正好遇到术语"弱一致性"(在堆栈溢出用户返璞词的答案,如何设置隐式转换允许数值类型之间的算术?).

它是什么?

ret*_*nym 20

3.5.3弱一致性在某些情况下,Scala使用更一般的一致性关系.类型S弱类型符合类型T,写入S <:w T,如果S <:T或S和T都是原始数字类型并且S在下面的顺序中在T之前.

  • 字节<:w
  • 字节<:w字符
  • 短<:w Int
  • Int <:w很
  • 长<:w Float
  • Float <:w Double

弱的最小上限是弱一致性的最小上限.

这在哪里使用?首先,它确定if表达式的类型:

条件表达式的类型是e2和e3类型的弱最小上界(§3.5.3)

在Scala 2.7.x中,这将是类型AnyVal,最小的IntDouble.的绑定.在2.8.x中,它键入为Double.

scala> if (true) 1 else 1d
res0: Double = 1.0
Run Code Online (Sandbox Code Playgroud)

同理:

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>
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

还有简单的数字扩展:

数字扩展.如果e具有与预期类型弱符合(§3.5.3)的原始数字类型,则使用6.26隐式转换97数字转换方法之一将其扩展为预期类型toShort,toChar,toInt,toLong,toFloat,toDouble在第12.2.1节中定义.expect类型是原始数字类型Byte,Short或Char,表达式e是在该类型范围内拟合的整数文字,它将转换为该类型中的相同文字.

scala> 1: Double
res10: Double = 1.0
Run Code Online (Sandbox Code Playgroud)

UPDATE

正如丹尼尔所指出的,关于哪些类型的弱一致性的规范是错误的.让我们问编译器本身:

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
Run Code Online (Sandbox Code Playgroud)


Von*_*onC 5

为了完成Sandor的回答,2.8中的新功能仍在烘焙(并且已修复).

这个帖子中,Esser发现了令人讨厌的副作用:

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 
Run Code Online (Sandbox Code Playgroud)

看起来很有趣,因为隐式找到的结果类型是Double,结果是3.0.
如果明确给出Double,结果是3.33 ......

这篇帖子中,Martin Odersky补充道(6月21日):

你已经在重载分辨率中发现了弱一致性规则的严重无意识的副作用.
问题是重载方法的参数需要弱化,而结果类型需要强烈符合.

此赞成Float => Float加入法上的Int在所述Int => Int方法如果结果是类型浮动.
我试图保持对弱一致性的改变,因为我只需要看到绝对必要的弱一致性.
但现在看来,保守派导致了我们正在关注的问题!

还有另一个Scala RC版本;)


Martin Odersky(6月22日)证实了这一主题:

所以到目前为止RC6会有一个RC7的三个变化:

  1. val x: Double = 10/3会给3.0,而不是3.3333333- 那是我提到的回归
  2. [...]
  3. [...]

而已.我们现在的优先事项是尽可能快地推出2.8,同时避免真正糟糕的回归,例如上面的(1).

时间线:

  • 我们将再等一周,以获得有关RC6的反馈.
  • 我们将在下周初推出RC7.
    如果没有其他问题出现,RC7将在发布后的最后10-14天变为2.8.

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