【问题标题】:Why doesn't "1 Math.pow 2" work in scala?为什么“1 Math.pow 2”在 scala 中不起作用?
【发布时间】:2019-09-26 23:47:09
【问题描述】:

在 scala 中以下工作

1 max 2

但以下不是

1 Math.pow 2

import Math.pow
1 pow 2

你能解释一下原因吗?

【问题讨论】:

  • 你的意思是math小写吗?
  • 我认为有一些重叠,但不是完全重复。 1 pow 2(和 1 Math.pow 2)问题是关于隐式转换 1 到 Int 后可用的方法(其中 pow 不是可用方法)。
  • 中缀符号很烂。

标签: scala


【解决方案1】:

这里发生了几件事。简而言之:

  • 将常量“1”隐式转换为 Int 实例
  • 对采用单个参数的方法利用“空格符号”

在 1 max 2 的情况下,常量 1 被隐式转换为 Int(即 Int 类的实例)。

由于 Int 类定义了一个名为“max”的方法,该方法采用单个参数,您可以使用空格或infix notation。以下都是等价的(在 spark-shell 中运行):

scala> 1 max 2
res8: Int = 2

scala> 1.max(2)
res9: Int = 2

scala> val x = 1     // Note the result type here is Int
x: Int = 1

scala> x.max(2)
res10: Int = 2

scala> x max (2)
res11: Int = 2

scala> 1            // Note the result type here is *also* Int
res12: Int = 1

scala> 1.           // Here are all of the methods that are defined for an Int
!=   +    <<   >>             byteValue     ensuring     formatted    isInfinity      isValidByte    isWhole     notify       signum           toChar        toInt           toString     until   
##   -    <=   >>>            ceil          eq           getClass     isInstanceOf    isValidChar    longValue   notifyAll    synchronized     toDegrees     toLong          unary_+      wait    
%    ->   ==   ^              compare       equals       hashCode     isNaN           isValidInt     max         round        to               toDouble      toOctalString   unary_-      |       
&    /    >    abs            compareTo     floatValue   intValue     isNegInfinity   isValidLong    min         self         toBinaryString   toFloat       toRadians       unary_~      →       
*    <    >=   asInstanceOf   doubleValue   floor        isInfinite   isPosInfinity   isValidShort   ne          shortValue   toByte           toHexString   toShort         underlying           

请注意,Int 上有很多可用的方法,例如 max、min、+、- 等等。查看 say, + 的签名,我们可以看到 + 是一个接受单个参数的方法。因此我们可以做到以下几点:

scala> 1 + 2     // No surprises here
res15: Int = 3

scala> 1.+(2)    // Huh? This works because + is a method of Int that takes a single parameter.
                 // This is effectively the same as your max example.
res16: Int = 3

scala> 1.+       // Here are the signatures of the + method.
   def +(x: Char): Int
   def +(x: Long): Long
   def +(x: Float): Float
   def +(x: Short): Int
   def +(x: Double): Double
   def +(x: Byte): Int
   def +(x: String): String
   def +(x: Int): Int

scala> 1 + 'A'   // From the above, we can see that the following is also valid
res17: Int = 66  // because the return type is Int

scala> 1 + "41"
res18: String = 141   // In this case, the + operator is a String concatenation operator Because the return type is String

scala> 1 + "x"
res19: String = 1x    // Also because the return is String, but possible more intuitive.


到问题的 pow 部分。

Math.pow 是一种采用 2 个参数的方法。因为它需要 2 个参数,所以您无法使用空格符号。 此外,pow 不是与 Int 关联的方法。它很像 Math 类的静态方法(实际上 Math 是一个对象)。所以,就像你不能说 x.pow(y,z) 你不能说 1.pow(y, z) 另一方面你可以说 Math.pow(x, 2) - 得到 x 平方 -因为这与 pow 方法的签名相匹配。

这是 Math.pow 的签名:

scala> Math.pow
   def pow(x$1: Double,x$2: Double): Double

这比 + 稍微不那么令人兴奋,但很明显它需要 2 个 Doubles 并返回一个 Double。即使将整数作为参数提供(当需要双精度时),说 Math.pow(2,2) 的示例仍然有效,因为 Ints 会自动转换为 Double。

我希望这有助于解释您所看到的。我鼓励您在 spark-shell、sbt 或其他一些 scala REPL 中尝试这些示例。

【讨论】:

    【解决方案2】:

    方法不一样的签名:

    override def max(that: Long): Long
    
    def pow(x$1: Double,x$2: Double): Double
    

    第一个是Int的成员*,可以在1上调用,而第二个在Math对象上调用,必须有两个参数。

    * 实际上是 RichInt 的隐式转换,但是从直观的使用角度来看,它涉及到同样的事情,所以这个微妙之处不应该打扰你

    【讨论】:

      【解决方案3】:

      方法:

      override def max(that: Int): Int = math.max(self, that)
      

      来自scala.runtime.RichInt class bc evry Int 被包装:

      @inline implicit def intWrapper(x: Int)         = new runtime.RichInt(x)
      

      scala.LowPriorityImplicits

      但是RichInt 没有任何pow 方法。而且您必须重新指定 Math.pow 签名:

      public static double pow(double a, double b)
      

      并使用 2 个参数调用它或使用您自己开发的包装器,例如:

      object MainClass {
      
        implicit class IntHelper(i:Int) {
          def pow(p:Int): Double = Math.pow(i, p)
        }
      
        def main(args: Array[String]): Unit = {
          println(1 pow 2)
        }
      }
      

      输出:

      1.0
      

      【讨论】:

        【解决方案4】:

        1 max 2 只是1.max(2) 的语法糖。

        由于1 是一个整数字面量,所有为scala.Int 定义的方法都可以通过这种方式应用。 不幸的是pow不是scala.Int的方法

        但是你可以在scala.math.BigDecimalscala.math.BigInt找到相关的方法。

        所以下面的方法会起作用:

        BigInt(1) pow 2
        

        【讨论】:

          【解决方案5】:

          你使用的max函数来自Int

          它的签名是:

          def max(that: Int): Int
          

          由于 1 是一个 Int,您可以使用中缀表示法调用 1 max 2。就是1.max(2)

          pow 函数来自Math。 它的签名是

          def pow(x: Double, y: Double): Double
          

          由于 1 不是数学,您不能简单地调用 1 pow 2。另一方面,在 Int 中,有 no 方法,例如 def pow(that: Int): Int

          您可以使用pow(a,2),它是数学实现。

          【讨论】:

            【解决方案6】:

            Scala.Math Documentation 表示pow 函数接受两个 Double 类型的参数,并返回第一个参数的第二个参数次方的值。

            这是pow函数的工作版本:

            import Math.pow
            
            val a: Double = 1
            
            pow(a,2) // returns 1.0
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-06-18
              • 2018-10-22
              • 2018-02-05
              • 1970-01-01
              • 2018-10-27
              • 1970-01-01
              • 1970-01-01
              • 2014-07-28
              相关资源
              最近更新 更多