In Java we can make a constructor using the class name. But in scala I have seen different uses of apply and unapply. Is this the same like the usage of a constructor in Java, in which we can use apply and unapply as a constructor?
问题:
回答1:
apply()
can be used as factory method (not a constructor), and it often is, but it is not restricted or required to be so. What makes apply()
special is just that it can be "silently" invoked.
class MyClass(arg: String) {
def apply(n: Int):String = arg*n
}
val mc = new MyClass("blah")
mc.apply(2) // res0: String = blahblah
mc(3) // res1: String = blahblahblah
You'll often see apply()
used as a factory method in a companion object.
object MyClass {
def apply(s: String): MyClass = new MyClass(s)
}
val mc = MyClass("bliss") // call the object's apply() method
But, again, that's just a convenient convention, not a requirement.
unapply()
(and unapplySeq()
) is different in that it is "silently" called whenever you attempt to pattern match on a class instance.
class MyClass(val arg: String) {}
object MyClass {
def unapply(x: MyClass): Option[String] = Some(x.arg)
}
val mc = new MyClass("bland")
mc match {
case MyClass(s) => println(s"got $s") // output: "got bland"
case _ => println("not")
}
回答2:
in java we can make a constructor using class name. but in scala I have seen different use of apply and unapply, is this the same like constructor in java, in which we can use apply and unapply as a constructor
No.
In Scala, the constructor is invoked using the new
operator (just like in Java) and is named this
(the primary constructor doesn't have a name at all, it is just the body of the class).
apply
and unapply
aren't constructors, they are methods. Methods are different from constructors in Scala (just like they are in Java). The only thing special about apply
is that foo()
gets interpreted as foo.apply()
if there is no method named foo
in scope. In other words, apply
allows you to make your own function-like objects.
unapply
is called when you try to "break apart" an object using Pattern Matching. It allows an object to decide which part of itself it will expose to pattern matching and how. In other words: it is required to preserve object-oriented data abstraction in the face of pattern matching.
Since the purpose of unapply
is to extract values from an object, it is in some sense the exact opposite of a constructor, whose purpose it is to collect values and hide them in an object.
回答3:
No, it's not. Apply
can call constructor but it's not the equal things, it came from functional programming paradigm. From Wikipedia: function application is the act of applying a function to an argument from its domain so as to obtain the corresponding value from its range. So, apply
it's just applying the function to argument, and yes in Scala monads classes, inside apply they usually call constructors. But in other functions apply can do different things.
Unapply
it's construction for pattern matching, but semantically it's vice versa operation to apply
. It says: give me object which was create by applying function to argument X, and I will return you this argument X.
回答4:
Apparently the difference is mostly in style. I prefer the usage of apply as it is more functional from the companion object perspective. But as Scala does not define destructor methods (like you do in C++) in the class , it becomes more natural to use apply as you might need to define the unapply method and would have a clear design explicitly defining both at the same level.