Type parameters applied to Scala Function

2020-04-21 02:47发布

问题:

I am trying to understand the type parameters when applied to a function.

I would like to use Generic Types in the below method but using String and Int for my understanding.

When I define a function as below

  def myfunc[Int](f:String => Int):Int =  {
    Integer.min(1,2)
  }

it complains

 found   : scala.this.Int
 required: Int&0
      Integer.min(1,2)

However if I remove the return type of the function ( which I understand is not required), it compiles fine.

I am not able to infer why removing the return type makes the compilation successful.

Appreciate your help.

-Amit

回答1:

Try

def myfunc(f:String => Int):Int =  {
  Integer.min(1,2)
}

When you write def myfunc[Int](f:String => Int):Int you declare type parameter Int, which hides standard type scala.Int. This is the same as if you declared def myfunc[A](f:String => A):A. When you remove return type it's inferred to be scala.Int, i.e. def myfunc[A](f:String => A) is def myfunc[A](f:String => A):Int



回答2:

If you want to use generics, first you have to understand that the name of the variable types starts capitalized and they are names, just that so [Int] in your function is the name of the type variable, an example:

object Main extends App{
    val f: String => Int = s => 4
    println(myfunc(f, "nothing useful"))

    def myfunc[A,B](f:A => B, x: A):B =  {
      f(x)
    }
}

here the names are A and B and the return type is of type B



回答3:

Question: What's the difference between these 3 methods?

def myfunc1[X](f:String => X):X =
  Integer.min(1,2)

def myfunc2[Int](f:String => Int):Int =
  Integer.min(1,2)

def myfunc3[IDontGetTypeParameters](f:String => IDontGetTypeParameters):IDontGetTypeParameters =
  Integer.min(1,2)

Answer: Nothing. From the compiler's point of view they are the same, and they fail to compile for the same reason: each is defined to return the type of the type parameter but tries to return an integer (Scala.Int) instead.



回答4:

A quick one liner:

def myfunc(f:String => Int):Int = Integer.min(1,2)


回答5:

It's good trying to make your own examples, but have you tried any examples from books, articles or tutorials? There's probably a good one in Scala for the Impatient by Cay Horstmann.

Here's a decent example from the Tour de Scala:

def listOfDuplicates[A](x: A, length: Int): List[A] = {
  if (length < 1)
    Nil
  else
    x :: listOfDuplicates(x, length - 1)
}

Sometimes you can omit the type parameter, but let's ignore that for now and declare the types explicitly:

listOfDuplicates[Int](43, 5) // Should give a list with 43 five times
listOfDuplicates[String]("Hello, world! ", 3) // "Hello, world!" thrice
listOfDuplicates[(Int, Int)]((0, 1), 8) // The pair (0, 1) eight times

This shows that A can be Int, String, (Int, Int) or just about anything else we can think of. Not sure you'd ever have a practical need for this, but you can even do something like this:

def wrapLength(str: String): Int = str.length

listOfDuplicates[String => Int](wrapLength(_), 2)

Here's a Scastie snippet in which you can play around with this.



回答6:

Your generic type name shouldn't be one of the reserved words in Scala. Int itself is a reserved word for a type. In this cases, for simplicity and understanding, we use some basic characters like T or R as the generic type if you really keen to use generics for other functions.