【问题标题】:Why does wrapping values in a code block change my typed numbers into Doubles?为什么在代码块中包装值会将我输入的数字更改为双精度数?
【发布时间】:2017-03-11 20:19:24
【问题描述】:

如果我用 3 调用它,我会按预期返回一个 Int 类型的返回值。

  def determineKind( a:Int ):Any = {
    if( a < 5 ) 
      a.toInt
    else if(a<50)
      a.toLong
    else if(a<100)
      a.toFloat
    else
      a.toDouble
  }

如果我用 3 调用它,我会得到一个 Double。

  def determineKind2( a:Int ):Any = {
    val aResult = { if( a < 5 ) 
      a.toInt  // Execution flows here
    else if(a<50)
      a.toLong
    else if(a<100)
      a.toFloat
    else
      println("Oops!") // Never executed--yet I get a Double back!
      a.toDouble  
    }
    aResult
  }

为什么?我不想要双份。 (真正的函数使用了一个 match/case 块,它似乎也将这些数字类型中的任何一个转换为 Double。)

在代码块中包装一些东西会触发不需要的类型更改为 Double。

为什么会这样?

【问题讨论】:

  • 你期望的类型是什么?
  • aResultmatch 语句具有相同的类型。 match 语句可以返回 IntLongFloatDouble 之一。 Double 是集合中最宽、最通用的类​​型,因此它是整个表达式的结果类型。

标签: scala


【解决方案1】:

你的问题在于你如何定义 if 块,在determineKind2 中,a.toDouble 总是分配给aResult,并且 if 块的整个结果被丢弃。

正在发生的事情的说明:

def block = {
  if(condition)
     v1
  else 
     println(v2)
     v2 
}

总是返回 v2。发生这种情况是因为使用显式花括号的相同代码是这样的:

def block = {
  if(condition) {
     v1
  } else {
     println(v2)
  }
     v2 
}

注意 v2 是如何在 if 块之外的。另一方面,如果语句块:

condition match {
  case true => v1
  case _    =>
    println(v2)
    v2
}

上面不会发生同样的情况,cases 中的块以相同范围深度的另一个案例的开头结束。

附带说明:缩进对块的编译方式没有任何影响。

【讨论】:

    【解决方案2】:

    这是一个棘手的情况,数字加宽开始发挥作用。在第一个示例中,您声明了返回类型Any,因此无需扩展任何类型。在第二种情况下,val aResult = 您要求 Scala 推断 if 表达式的类型,它会避免推断 Any,而是决定将各个类型在数字上扩大到 Double。通常这种扩大是你想要的,例如假设你写的是 Seq(1, 2.3, 4.5) - 你会期望它是 Seq[Double] 而不是 Seq[Any]

    如果你定义aResult的类型,你要求Scala接受Any的非特定类型:

    def determineKind(a: Int): Any = {
      val res: Any /* ! */ = if (a < 5)
        a.toInt
      else if (a < 50)
        a.toLong
      else if(a < 100)
        a.toFloat
      else
        a.toDouble
    
      res
    }
    
    assert(determineKind(3).isInstanceOf[Int])
    

    数字加宽出现在Scala Language Specification 的第 6.26.1 节中:

    如果 e 有一个原始数字类型 weakly conforms 到预期类型,则使用数字转换方法之一将其扩展为预期类型 toShorttoChar、@987654336 @、toLongtoFloattoDouble 定义为here

    【讨论】:

    • 我建议在他的第二种方法中仔细查看ifexpression 的末尾。
    • 对,我没看到那个位
    【解决方案3】:

    Greg,下面这个块返回 Double 类型的值,因为你在其中做的最后一件事是调用 a 上的 toDouble 方法。

    val aResult = {
        if( a < 5 ) 
          a.toInt  // Execution flows here
        else if(a<50)
          a.toLong
        else if(a<100)
          a.toFloat
        else
          println("Oops!") // Never executed--yet I get a Double back!
          a.toDouble // <---- this line is not a part of if else expression
    }
    

    这是使用花括号的一个很好的理由,这样你就可以防止这样的错误。

    【讨论】:

      猜你喜欢
      • 2018-12-23
      • 1970-01-01
      • 1970-01-01
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多