What's the difference between => , ()=>, and Unit=>

后端 未结 4 1789
深忆病人
深忆病人 2020-11-22 16:40

I\'m trying to represent a function that takes no arguments and returns no value (I\'m simulating the setTimeout function in JavaScript, if you must know.)

c         


        
4条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-11-22 17:38

    Call-by-Name: => Type

    The => Type notation stands for call-by-name, which is one of the many ways parameters can be passed. If you aren't familiar with them, I recommend taking some time to read that wikipedia article, even though nowadays it is mostly call-by-value and call-by-reference.

    What it means is that what is passed is substituted for the value name inside the function. For example, take this function:

    def f(x: => Int) = x * x
    

    If I call it like this

    var y = 0
    f { y += 1; y }
    

    Then the code will execute like this

    { y += 1; y } * { y += 1; y }
    

    Though that raises the point of what happens if there's a identifier name clash. In traditional call-by-name, a mechanism called capture-avoiding substitution takes place to avoid name clashes. In Scala, however, this is implemented in another way with the same result -- identifier names inside the parameter can't refer to or shadow identifiers in the called function.

    There are some other points related to call-by-name that I'll speak of after explaining the other two.

    0-arity Functions: () => Type

    The syntax () => Type stands for the type of a Function0. That is, a function which takes no parameters and returns something. This is equivalent to, say, calling the method size() -- it takes no parameters and returns a number.

    It is interesting, however, that this syntax is very similar to the syntax for a anonymous function literal, which is the cause for some confusion. For example,

    () => println("I'm an anonymous function")
    

    is an anonymous function literal of arity 0, whose type is

    () => Unit
    

    So we could write:

    val f: () => Unit = () => println("I'm an anonymous function")
    

    It is important not to confuse the type with the value, however.

    Unit => Type

    This is actually just a Function1, whose first parameter is of type Unit. Other ways to write it would be (Unit) => Type or Function1[Unit, Type]. The thing is... this is unlikely to ever be what one wants. The Unit type's main purpose is indicating a value one is not interested in, so doesn't make sense to receive that value.

    Consider, for instance,

    def f(x: Unit) = ...
    

    What could one possibly do with x? It can only have a single value, so one need not receive it. One possible use would be chaining functions returning Unit:

    val f = (x: Unit) => println("I'm f")
    val g = (x: Unit) => println("I'm g")
    val h = f andThen g
    

    Because andThen is only defined on Function1, and the functions we are chaining are returning Unit, we had to define them as being of type Function1[Unit, Unit] to be able to chain them.

    Sources of Confusion

    The first source of confusion is thinking the similarity between type and literal that exists for 0-arity functions also exists for call-by-name. In other words, thinking that, because

    () => { println("Hi!") }
    

    is a literal for () => Unit, then

    { println("Hi!") }
    

    would be a literal for => Unit. It is not. That is a block of code, not a literal.

    Another source of confusion is that Unit type's value is written (), which looks like a 0-arity parameter list (but it is not).

提交回复
热议问题