5 + 5
is quite valid, and will generate a new object in the heap, which the garbage collector will quickly streamline (in fact, I quietly hope that the compiler will understand the depth of the plan and generate nothing :)).
object Main {
def main(args:Array[ String ]) :Unit = {
print( "Hello, " + args(0) + "!" )
}
}
<>
us <>
that we are used to, but seemingly forever assigned to the arrays []
.()
.println( ( "Hello, " + args(0) + "!" ).toUpperCase )
println( "Hello, " + args(0) + "!" toUpperCase )
.
absolutely not necessary. The language syntax fully allows the use of a space instead (you can also write method arguments without brackets and commas immediately after the method name). And as we see, this turns out to be quite useful: in the first line there is a high-priority operator .
makes us write unnecessary cluttering code brackets, in the second we get a more concise and clear form of writing.
$ scala
Welcome to Scala version 2.7.3final (Java HotSpot(TM) Server VM, Java 1.6.0_16).
Type in expressions to have them evaluated.
Type :help for more information.
scala>
scala> 1 to 10
res0: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Int
1 calls the method to
with a parameter of the same type 10, the result is a range of values.
scala> def sum(a: Int, b: Int): Int = {
| var result = 0
| for (i <- a to b) result += i
| result
| }
sum: (Int,Int)Int
scala> sum(1, 5)
res3: Int = 15
scala> def sum(f: Int => Int, a: Int, b: Int): Int =
| if (a > b) 0 else f(a) + sum(f, a + 1, b) sum: ((Int) => Int,Int,Int)Int
=>
means that the parameter is a function, the types of accepted values are listed to its left in parentheses (if the parameter is one, as in this example, they can be omitted), the type of the returned result is to the right.
if
is an expression that has a value (by the way, the previously used for
is also an expression, its result is of type Unit
). If the condition is true, then its result is the first option, otherwise the second one.
id
and square
, they are equal to their parameter and its square, respectively.
scala> def id(x: Int): Int = x
id: (Int)Int
scala> def square(x: Int): Int = x * x
square: (Int)Int
scala> sum(id, 1, 5)
res1: Int = 15
scala> sum(square, 1, 5)
res2: Int = 55
class Complex(r: Double, i: Double) {
def real = r
def image = i
def magnitude = Math .sqrt(r*r + i*i)
def angle = Math .atan2(i, r)
def + (that: Complex) = new Complex( this .real + that.real, this .image + that.image)
override def toString = real+ " + i*" +image+ " | " +magnitude+ "*e^(i*" +angle+ "))"
}
object Main {
def main(args:Array[ String ]) :Unit = {
val first = new Complex(1, 5)
val second = new Complex(2, 4)
val sum = first + second
println(first)
println(second)
println(sum)
}
}
Complex
and returns it.
toString
function, which is familiar to all Java programmers, is toString
. It is important to note that overriding methods in Scala should always be explicitly indicated using the override
keyword.
class Complex(val real: Double, val image: Double) extends Ordered[Complex] {
def magnitude = Math .sqrt(real*real + image*image)
def angle = Math .atan2(image, real)
def + (that: Complex) = new Complex( this .real + that.real, this .image + that.image)
def compare(that: Complex): Int = this .magnitude compare that.magnitude
override def toString = real+ " + i*" +image+ " | " +magnitude+ "*e^(i*" +angle+ "))"
}
object Main {
def main(args:Array[ String ]) :Unit = {
val first = new Complex(1, 5)
val second = new Complex(2, 4)
if (first > second )
println( "First greater" )
if (first < second )
println( "Second greater" )
if (first == second )
println( "They're equal" )
}
}
Ordered
declares the abstract method compare
and, on its basis, complements the successor class with <, <=,>, etc. It should be noted here that in a good way it is worth redefining the operator == provided to us, since it also gives truth for non-identical objects, and equals methods with hashCode should also be redefined in such cases.
class User {
private [ this ] var _name: String = ""
def name = _name toUpperCase
def name_=(name: String ) = {
_name = if (name != null ) name else ""
}
}
var
, which is already familiar to us, in its body, and not just but with the outlandish modifier private[this]
. The meaning of this keyword in the class body is absolutely similar to that in the inside of the block (and even, I will tell you a secret, you can also cram it into the constructor) and from the name after it makes a variable attribute of the class. The outlandish modifier states that a variable should be available only to this object. It was possible to write, for example, private[User]
and it would become available to other, us similar, objects, or specify the name of the package ( something reminds me of it).name_=
, the strange function name_=
, which receives a string as a parameter, checks that it is not null
and writes it to our field.val user = new User( "Scala!!!" )
println(user.name)
user.name = "M. Odersky"
println(user.name)
SCALA!!!
M. ODERSKY
()
to the call of the apply
method), case
keyword, after which the compiler takes the liberty to do the following:
match
method. Let's take a look at an example:
abstract class User
case class KnownUser(val name: String ) extends User
case class AnonymousUser() extends User
object Test {
val users = List (KnownUser( "Mark" ), AnonymousUser(), KnownUser( "Phil" ))
def register(user: User): Unit = user match {
case KnownUser(name) => println( "User " + name + " registered" )
case AnonymousUser() => println( "Anonymous user can't be registered" )
}
def main(args: Array[ String ]) =
users. foreach ( register )
}
match
method. For each case expression, it performs a check on the type matches the class of the template and the matching of the constructor parameters to the template. A template in general can include:
_
denoting any meaning that does not interest us.1
or "Hello"
. "Hello"
null
and checked every time (aesthetes like me turn on methods like isAnonymous
, consisting of comparing fields with the same null
). The problems are obvious - implicitly and insecurely. There are a great number of such examples, when different variations of the structure of objects are combined into one class, and those that are not used in a particular case get clogged up with nulls, or even worse, the default value is invented. Scala allows you to explicitly describe variations in the structure of objects, and provides a convenient mechanism for working with these variations.
def s = "Scala"
compiler will define the type of the constant as a string. All this also works on generic types, for example, the fragment above val users = List(KnownUser("Mark"), AnonymousUser(), KnownUser("Phil"))
creates a constant of type List[User]
, automatically rising to a suitable level in the hierarchy inheritance and using it to parameterize a container type. In practice, this means that you can save a lot on such ads (for fun, write one that does the same code in Java or C # :)).
Source: https://habr.com/ru/post/77750/