1. 程式人生 > >by name parameter & _的用法

by name parameter & _的用法

mat mil 計算 n) load numeric ons spa match

關於byname byvalue何時計算的問題

A by-name parameter acts like a def.

Scala has a solution to this problem called by-name parameters. By declaring a parameter as a: => A (note that the space after the : is necessary) we are telling Scala to evaluate a only when it is used (which may be never). So let’s fix our method.

def when[A](test: Boolean, whenTrue: A, whenFalse: A): A = 
  test match {
    case true  => whenTrue
    case false => whenFalse
  }

scala> when(1 == 2, "foo", "bar")
res13: String = bar

scala> when(1 == 1, "foo", "bar")
res14: String = foo

// Ok so far, but...

scala> when(1 == 1, println("foo"), println("bar"))
foo
bar

def when[A](test: Boolean, whenTrue: 
=> A, whenFalse: => A): A = test match { case true => whenTrue case false => whenFalse } // Try that again... scala> when(1 == 1, println("foo"), println("bar")) foo scala> when(1 == 2, println("foo"), println("bar")) bar

When we talk about laziness we mean that an expression is reduced by need, as is the case with lazy val

in Scala.

val a = { println("computing a"); util.Random.nextInt(10) }
def a = { println("computing a"); util.Random.nextInt(10) }
List(a, a, a, a, a)//及時計算

def five[A](a: => A): List[A] = List(a, a, a, a, a)
five { println("computing a"); util.Random.nextInt(10) }//by name 也及時計算

lazy val a = { println("computing a"); util.Random.nextInt(10) }
def five[A](a: => A): List[A] = { lazy val b = a; List(b, b, b, b, b) }
five { println("computing a"); util.Random.nextInt(10) }
//這裏lazy後不計算
//lazy val is computed once like any other val, but not until its value is needed.

So although we used by-name parameters to implement lazy behavior for our when function above, this is dependent on only referencing each parameter once.

A parameter is strict if its argument is always evaluated, regardless of calling convention; in our five function above our parameter is both by-name and strict.

reference a by-name parameter without forcing its evaluation:can apply η-expansion (put an underscore after the identifier) to turn it into a function value.

所以說,when中實現了lazy是因為對每個parameter只引用一次。

若需要引用by-name parameter,但又不想計算,則可以在identifier後加上_轉為function value。_作用是we construct a Function1 instance that delegates to our method. (val f = add1 _)

scala> def foo(a: => Unit): () => Unit = a _
foo: (a: => Unit)() => Unit

scala> val z = foo(println("hi"))
z: () => Unit = <function0>

scala> z()
hi

以下幾個情景使用 _ :

函數的類的實例賦給val(不用_則需要聲明類型信息, 調用新名稱時需要()),map以函數作參對每一個元素操作,

多個參數時:如果有默認arguments則不能partial application

Values in scala cannot have type parameters; when η-expanding a parameterized method all type arguments must be specified (or they will be inferred as non-useful types): 即所有類型參數必須指明,否則為無用類型

val g = new Function1[Int, Int] { def apply(n: Int): Int = add1(n) }

scala> List(1,2,3).map(add1 _)
res5: List[Int] = List(2, 3, 4)

scala> List(1,2,3).map(add1)
res6: List[Int] = List(2, 3, 4)


scala> val z = add1//需要賦予類型信息
<console>:8: error: missing arguments for method add1;
follow this method with `_if you want to treat it as a partially applied function
       val z = add1
               ^

scala> val z: Int => Int = add1
z: Int => Int = <function1>

scala> val z = add1 : Int => Int
z: Int => Int = <function1>

scala> "foo".substring _
<console>:8: error: ambiguous reference to overloaded definition,
both method substring in class String of type (x$1: Int, x$2: Int)String
and  method substring in class String of type (x$1: Int)String
match expected type ?
              "foo".substring _
                    ^

scala> "foo".substring _ : (Int => String)
res14: Int => String = <function1>

scala> def x = println("hi")
x: Unit

scala> val z = x // ok
hi
z: Unit = ()

scala> val z = x _
z: () => Unit = <function0>

scala> z()
hi
----------- 
scala> def plus(a: Int, b: Int): Int = a + b
plus: (a: Int, b: Int)Int

scala> plus _
res8: (Int, Int) => Int = <function2>


scala> def plus(a: Int)(b: Int): Int = a + b
plus: (a: Int)(b: Int)Int

scala> plus _
res11: Int => (Int => Int) = <function1>
 
scala> plus(1)
<console>:9: error: missing arguments for method plus;
follow this method with `_if you want to treat it as a partially applied function
              plus(1)
                  ^

scala> plus(1) _
res13: Int => Int = <function1>

scala> val x = plus _
x: Int => (Int => Int) = <function1>

scala> x(1) // no underscore needed
res0: Int => Int = <function1>

-------------#implicit members
scala> def foo[N:Numeric](n:N):N = n
foo: [N](n: N)(implicit evidence$1: Numeric[N])N

scala> foo[String] _
<console>:9: error: could not find implicit value for evidence parameter of type Numeric[String]
              foo[String] _
                 ^

scala> foo[Int] _
res3: Int => Int = <function1>

scala> def bar[N](n:N)(implicit ev: Numeric[N]):N = n
bar: [N](n: N)(implicit ev: Numeric[N])N

scala> bar[Int] _
res4: Int => Int = <function1>
-------------
scala> def foo(n: Int = 3, s: String) = s * n
foo: (n: Int, s: String)String

scala> foo _
res19: (Int, String) => String = <function2>

scala> foo(42) _
<console>:9: error: not enough arguments for method foo: (n: Int, s: String)String.
Unspecified value parameter s.
              foo(42) _
 

by name parameter & _的用法