【问题标题】:Defining function using val使用 val 定义函数
【发布时间】:2018-02-17 11:49:20
【问题描述】:

我知道在 scala 中使用 def/val 定义函数的基本区别:如果我使用 val,我的函数被定义一次,如

scala> val valRandom = Random.nextInt
valRandom: Int = 2032538454

scala> valRandom
res0: Int = 2032538454

但我的问题是为什么每次我使用如下函数时都会计算 Random.nextInt:

scala> val valRandom2 = (_:Int) + Random.nextInt
valRandom2: Int => Int = $$Lambda$1100/1597979904@1a6dc5ea

scala> valRandom2(0)
res2: Int = 486047489

scala> valRandom2(0)
res3: Int = 1573520480

【问题讨论】:

  • 你认为它应该做什么?变量是值,函数是计算。当您引用之前为其分配值的变量时,您将获得之前分配的值。当您引用一个函数时,它会运行该计算...
  • 我希望它计算一次 Random.nextInt 值,然后将其添加到我传入 valRandom2 的参数中,因此每次使用相同的参数时,我都会得到相同的结果
  • 我的意思是,如果我在我的 valRandom2 中添加带有一些文本的打印行,我可以看到 println 在定义新函数时只被评估一次,但我很好奇为什么 Random.nextInt 是稍后计算的,当函数叫什么?

标签: scala function


【解决方案1】:

在您的第一种方法中,

scala> val valRandom = Random.nextInt
valRandom: Int = 2032538454

如果您注意到valRandom 的类型是int。基本上,您已经使用 Random.nextInt 初始化了 valRandom。

但是,在第二种方法中,

scala> val valRandom2 = (_:Int) + Random.nextInt
valRandom2: Int => Int = $$Lambda$1100/1597979904@1a6dc5ea

您注意到valRandom2 的类型映射自Int -> Int valRandom2 是一个函数值,它只是一个匿名函数或 lambda 表达式。

因此,每当您调用它时,它总会产生新的价值。

这两种方法的区别在于,第一种方法是创建一个变量并为其分配随机值。但是在第二种方法中,您正在调用匿名函数,因此它每次都会评估

【讨论】:

    【解决方案2】:

    在 valRandom2 中,随机偏移量是在函数体内计算的,因此每次调用函数时都会计算它。

    你需要计算函数外的随机偏移量,像这样:

    val valRandom3 = { val rand = Random.nextInt; (_:Int) + rand }
    

    【讨论】:

      【解决方案3】:

      我的回复:

      scala>  val valRandom2 = (_:Int) + Random.nextInt
      valRandom2: Int => Int = <function1>
      

      所以 valRandom2 是一个东西,它接受一个 Int 并返回一个 Int,并且是 function1 类型。例如:

      scala>  val valRandom3 = (_:Int) + (_:Int) + Random.nextInt
      valRandom3: (Int, Int) => Int = <function2>
      

      这是 function2 类型。

      数字 (1, 2) 表示传入了多少个参数。函数总是返回一个值,所以这无关紧要。即使没有返回,因为它是一个过程,可能是为了副作用而调用的,它隐式返回 Unit()。如果它返回某物或元组的列表,那只是一件事,您必须将其分解,才能获得多个值之一。

      函数与方法不同。函数可以传递,延迟执行,方法可以直接调用,但是方法很容易作为函数传递。

      scala> def add (a: Int, b:Int) : Int = a + b
      add: (a: Int, b: Int)Int
      
      scala> def mul (a: Int, b:Int) : Int = a * b
      mul: (a: Int, b: Int)Int
      
      scala> def printIt (a: Int, b:Int, f:(Int, Int) => Int) = {
           |   val c = f (b, a) 
           |   println (s"b $b (X) a $a = c $c") 
           | }
      printIt: (a: Int, b: Int, f: (Int, Int) => Int)Unit
      
      scala> printIt (3, 4, add) 
      b 4 (X) a 3 = c 7
      
      scala> printIt (3, 4, mul) 
      b 4 (X) a 3 = c 12
      

      这个例子虽然很容易理解,但并没有解释它为什么有用,但有用的例子设置起来更复杂。但是想象一个可以对数值进行排序的列表。如果您有一个员工列表,您可以通过将函数传递给列表来对它们进行排序,以从员工中获取数字,无论是 Employee.id、*.age、*.maxSalary ()、.address.zipCode 还是无论如何,这会给你最大的灵活性。

      到评论:

      scala>  val valRandom2 = {println ("vR2 called"); (_:Int) + Random.nextInt}
      vR2 called
      valRandom2: Int => Int = <function1>
      
      scala> val x = valRandom2 (0)
      x: Int = -1231081
      
      scala> val x = valRandom2 (0)
      x: Int = 1421497830
      

      为什么在声明时打印,而在使用时执行nextInt?

      因为

      scala>  val valRandom2 = {println ("vR2 called"); (_:Int) + Random.nextInt}
      vR2 called
      valRandom2: Int => Int = <function1>
      
      scala>  val valRandom2 = {println ("vR2 called"); (_:Int) + Random.nextInt}
      vR2 called
      valRandom2: Int => Int = <function1>
      
      scala> val x = valRandom2
      x: Int => Int = <function1>
      

      rhs 的结果是函数,它被分配给 valRandom2 或 x,而 print 是声明的副作用。该块作为其最后一个表达式返回函数。

      交换 valRandom2 上的内部调用,你什么也得不到(单位)。

      将参数 Int 添加到第二次调用中:

      scala>  val valRandom3 = {Random.nextInt; (_:Int) => println ("vR2 called") }
      valRandom3: Int => Unit = <function1>
      
      scala> valRandom3 (0)
      vR2 called
      
      scala> valRandom3 (0)
      vR2 called
      

      【讨论】:

        猜你喜欢
        • 2023-04-09
        • 2013-11-05
        • 1970-01-01
        • 2015-08-07
        • 2013-09-24
        • 2021-07-06
        • 2014-10-07
        • 2018-10-30
        相关资源
        最近更新 更多