问题
I have been confused about this for a while, even despite reading the Scala Style Guide - Method Invocation several times.
I want to be able to call this method
def foldRVL[A,B](l: List[A], z: B)(f: (A, B) => B) = //"Right-Via-Left"
l.reverse.foldLeft(z)((a, b) => f(b, a))
using dot notation like this List(1,2,3).foldRVL(0)(_ + _)
.
And not like this: foldRVL(List(1,2,3), 0)(_ + _)
.
Also, sometimes I've seen code that shows methods that actually either takes zero parameters in their signature, or one fewer parameters than I would expect them to take, and still properly take a parameter using dot-notation. How does this work? I ask this because those methods work with dot-notation, so maybe if I wrote something like that I could solve my problem.
回答1:
For the first part of your question, you probably need to look at implicit classes:
implicit class RichRVLList[A](l:List[A]) {
def foldRVL[B](z: B)(f: (A, B) => B) = //"Right-Via-Left"
l.reverse.foldLeft(z)((a, b) => f(b, a))
}
List(1,2,3).foldRVL(1)(_ + _) // output: res0: Int = 7
You can "enrich" existent class using implicit wrapper to "add" new methods.
As for the second part, probably you want implicit parameters. Implicit parameters are deduced from the current scope by type. There are some predefined implicit values, such as Numerics
, that were used in the example below:
def product[T](els:TraversableOnce[T])(implicit num:Numeric[T]) = {
els.fold(num.one)((x1, x2) => num.times(x1, x2))
}
product(List(1, 2, 3)) // res1: Int = 6
product(List(1, 2.5, 3)) //res2: Double = 7.5
回答2:
soong pointed out that I'm actually seeking the 'Pimp my library' pattern, which I then looked up, and implemented like this to handle the method in question:
implicit class BlingList[+A](l: List[A]) {
def foldRVL[B](z: B)(f: (A, B) => B): B = //"Right-Via-Left"
l.foldLeft(z)((a, b) => f(b, a))
}
As far as I understand, the key element to allowing dot-notation is having a class construct that takes parameters of the type that I want to have 'pimped'. In this case, I have a list, and I want to call foldRVL
on the list after I write the list down, like this:
List(something).foldRVL(z)(f: A => B)
.
Therefore, I need a class that takes a List[A]
parameter for me to be able to write a method like that in the first code snippet.
The implicit
keyword is used so that I can add methods to the existing class List
without having to create a separate Library of methods. Anytime a List
is found prefixed before foldRVL
, it will be implicitly converted into a BlingList
because the compiler will see a List
attached to a method that doesn't exist in class List
. It will therefore look for any implicit methods defined in scope that have a foldRVL
method and take a List
as an argument, and it finds that the implicit class BlingList
has the method foldRVL
defined and takes a List[A]
. Therefore, I can now write:
List(1,2,3).foldRVL(0)(_ + _) // in some IDE's, foldRVL will be underlined to show that
res0: Int = 6 // an implicit conversion is being made
"A Scala 2.10 implicit class example" goes into more depth about this. My favorite pointer from that post is to put all the implicit classes that you expect to be using in your current package and any subpackages inside of a package object
, that way you don't have to clutter any of your classes or objects with implicit class definitions, nor do you have to import them. The fact that they are using the same package will automatically import them thanks to the package object
.
来源:https://stackoverflow.com/questions/31621321/scala-how-can-i-create-a-function-that-allows-me-to-use-dot-notation-when-calli