Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is Scala?

2025-01-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Editor to share with you what Scala is, I believe that most people do not know much about it, so share this article for your reference, I hope you will learn a lot after reading this article, let's go to understand it!

Scala is a high-level programming language based on JVM, which combines the advantages of object-oriented programming and functional programming. In "Scala programming Guide with fewer words and more things," we have seen Scala's concise, scalable, and efficient syntax in several ways. We have also described many of the features of Scala. This article is the third chapter of Programming Scala, and we will finish explaining the nature of Scala before delving into Scala's support for object-oriented programming and functional programming.

Scala essence

Before we dive into Scala's support for object-oriented programming and functional programming, let's discuss some of the nature and features of Scala that may be used in programs in the future.

Operator? Operator?

An important basic concept of Scala is that all operators are actually methods. Consider the following most basic example.

/ / code-examples/Rounding/one-plus-two-script.scala 1 + 2

What is the plus sign between two numbers? It's one way. First, Scala allows non-character method names. You can name your method +, -, $, or any other name you want. Second, this expression is equivalent to 1. + (2). We added a space after 1 because 1. Will be interpreted as a Double type. Scala allows you not to write periods and parentheses when a method has only one parameter, so a method call looks like an operator call. This is called the infix notation, where the operator is between the instance and the parameter. We will see many examples of this soon.

Similarly, a method without parameters can be called directly without a period. This is called "suffix notation".

Ruby and SmallTalk programmers should feel as friendly as at home by now. Because those language users know that these simple rules have broad benefits, they allow you to create applications in a natural and elegant way.

So, which characters can be used in identifiers? Here is a summary of identifier rules that apply to the names of methods, types, variables, and so on. For a more precise description, see [ScalaSpec2009]. Scala allows all printable ASCII characters, such as letters, numbers, underscores, and the dollar sign $, except for characters like parentheses, such as'(','),'[','],'{','}', and delimited characters such as'',';', and','. In addition to the list above, Scala also allows other characters between u0020 and u007F, such as mathematical symbols and "other" symbols. These remaining characters are called operator characters, including'/','.

◆ =!

◆:

◆ +-

◆ * /%

All other special characters of ◆

Characters on the same line have the same priority. One exception is that when = exists as an assignment, it has the lowest priority.

Because * and / have the same priority, the behavior of the next two lines of scala conversation is the same.

Scala > 2.0 * 4.0 / 3.0 * 5.0res2: Double = 13.3333333333332 scala > ((2.0 * 4.0) / 3.0) * 5.0) res3: Double = 13.3333333333332

In a left-bound method call sequence, they are simply bound from left to right. Did you say "left binding"? In Scala, any method that ends with a colon: is actually bound on the right, while other methods are bound on the left. For example, you can use the:: method (called "cons", an abbreviation for "constructor" constructor) to insert an element before a List.

Scala > val list = List ('baked,' clocked,'d') list: List [Char] = List (b, c, d) scala >'a':: list res4: List [Char] = List (a, b, c, d)

The second expression is equivalent to list.:: (a). In a right-bound method call sequence, they are bound from right to left. What about expressions with left binding and mixed binding?

Scala >'a':: list + + List ('estranged,' f') res5: List [Char] = List (a, b, c, d, e, f)

(the + + method links two list. In this example, list is added to the List (eMaginf), and then an is inserted in front to create the final list. Usually we'd better add parentheses to eliminate possible uncertainties.

Prompt

Any method whose name ends with: is bound to the right, not the left.

Finally, notice that when you use the scala command, it looks as if you can define "global" variables and methods outside of the type, whether interactively or using scripts. This is an illusion; the interpreter actually contains all the definitions in an anonymous type before generating JVM or .NET CLR bytecode.

Domain specific language

Domain-specific language, also known as DSL, provides a convenient semantic way to express one's goals for a specific problem domain. For example, SQL provides just the right programming language functionality for dealing with databases, making it a domain-specific language.

Some DSL are self-contained like SQL, but it has become popular to use mature languages to implement DSL as a subset of the parent language. This allows programmers to take full advantage of the host language to cover marginal situations that DSL cannot cover, and saves time writing lexical parsers, parsers, and other language foundations.

The rich and flexible syntax of Scala makes it easy to write DSL. You can think of the following example as a style of writing behavior-driven development [BDD] programs using the Specs library (see the "Specs" section).

/ / code-examples/Rounding/specs-script.scala / / Example fragment of a Specs script. Doesn't run standalone "nerd finder" should {"identify nerds from a List" in {val actors = List ("Rick Moranis", "James Dean", "Woody Allen") val finder = new NerdFinder (actors) finder.findNerds mustEqual List ("Rick Moranis", "Woody Allen")}}

Notice the similarity between this code and the English syntax: "this should test that in the following scenario (this should be tested in the following scenarios)", "this value must equal that value (this value must be equal to that value)", and so on. This example uses the gorgeous Specs library, which provides an efficient set of DSL for behavior-driven development testing and engineering methodologies. By maximizing the use of Scala's native syntax and many methods, the Specs test team is readable even to non-developers.

This is just a simple attempt at Scala's powerful DSL. We'll see more other examples later, as well as learning how to write your own DSL when discussing more advanced topics (see Chapter 11-Domain specific languages of Scala).

Scala if instruction

Even the most common language features have been enhanced in Scala. Let's look at the simple if instructions. Like most languages, Scala's if tests a conditional expression and then jumps to a response block based on whether the result is true or false. A simple example:

/ code-examples/Rounding/if-script.scala if (2 + 2 = = 5) {println ("Hello from 1984.")} else if (2 + 2 = = 3) {println ("Hello from Remedial Math class?")} else {println ("Hello from a non-Orwellian future.")}

What is unusual in Scala is that if and almost all other instructions are actually expressions. So, we can assign the result of one if expression to other (variables), as shown in the following example:

/ / code-examples/Rounding/assigned-if-script.scala val configFile = new java.io.File (".myapprc") val configFilePath = if (configFile.exists ()) {configFile.getAbsolutePath ()} else {configFile.createNewFile () configFile.getAbsolutePath ()}

Note that if statements are expressions, meaning they have values. In this example, the value of configFilePath is the value of the if expression, which handles the case where the configuration file does not exist and returns the absolute path to the file. This value can now be reused in the program, and the value of the if expression is evaluated only when it is used.

Because the if statement is an expression in Scala, there is no need for triple conditional expressions for type C sublanguages. You won't see x in Scala? Code such as doThis (): doThat (). Because Scala provides a mechanism that is both powerful and more readable.

What happens if we omit the else sentence in the above example? Typing the following code into the scala interpreter will tell us what happened.

Scala > val configFile = new java.io.File ("~ / .myapprc") configFile: java.io.File = ~ / .myapprc scala > val configFilePath = if (configFile.exists ()) {| configFile.getAbsolutePath () |} configFilePath: Unit = () scala >

Notice that configFilePath is now of type Unit. (it used to be String. Type inference selects a type that satisfies all the results of the if expression Unit is the only possibility, because no value is also a possible result.

Scala for derivation statement

Another similar control structure that Scala has rich features is the for loop, also known as for derivation statements or for expressions in the Scala community. This function of language is definitely worthy of a fancy name, because it can do some cool tricks.

In fact, the term comprehension comes from functional programming. It expresses the idea that we are traversing a certain set, "deriving" what we have found, and then calculating something new from it.

A simple example of a puppy

Let's start with a basic for expression:

/ code-examples/Rounding/basic-for-script.scala val dogBreeds = List ("Doberman", "Yorkshire Terrier", "Dachshund", "Scottish Terrier", "Great Dane", "Portuguese Water Dog") for (breed format ("% s", head) processList (tail) case Nil = > println (")} for (" This has two things: "+ thingOne +" and "+ thingTwo)}}

In the second case in the example, we have solved the values in the tuple and attached them to the local variables, and then used these variables in the resulting expression.

In the first case, we added a new concept: Guard. The if condition after this tuple is a guard. The guard will evaluate the match, but will only solve the variables of this case. The guards provide additional dimensions when constructing the cases. In this case, the only difference between the two patterns is the guard expression, but this is enough for the compiler to distinguish between them.

Prompt

Recall that the cases of a pattern match is evaluated sequentially. For example, if your first case is wider than your second case, then the second case will not be executed. Unexecutable code can cause a compilation error. You can include a "default" default case at the end of the pattern match, using underscore wildcards, or meaningful variable names. When using a variable, it should not be explicitly declared as any type unless it is Any, so that it can match everything. On the other hand, try to design your code to circumvent such an one-size-fits-all condition and ensure that it only accepts specified expected items.

Case class matching

Let's try a deep match to check the contents of the object in our pattern matching.

/ code-examples/Rounding/match-deep-script.scala case class Person (name: String, age: Int) val alice = new Person ("Alice", 25) val bob = new Person ("Bob", 32) val charlie = new Person ("Charlie", 32) for (person println ("Hi Alice!") Case Person ("Bob", 32) = > println ("Hi Bob!") Case Person (name, age) = > println ("Who are you," + age + "year-old person named" + name + "?)}}

As we can see from the output of the above example, poor Charlie is ignored:

Hi Alice! Hi Bob! Who are you, 32 year-old person named Charlie?

We define a case class, a special type of class, which we will learn more in the "Case Class" section of Chapter 6-Scala Advanced object-oriented programming. For now, all we need to know is that a case class allows the construction of refined simple objects, as well as some predefined methods. Then, our pattern matching looks for Alice and Bob by checking the value of the Person case class passed in. Charlie was not captured until the last hungry case; although he was the same age as Bob, we also checked the name attribute.

As we will see later, this type of pattern matching can be very useful when working with Actor. Case classes are often sent to Actor as messages, and deep pattern matching of the contents of an object is a convenient way to "analyze" these messages.

Regular expression matching

Regular expressions are convenient for extracting data from strings with informal structures, but not for "structured data" (that is, formats like XML, or JSON). Regular expression is one of the common features of almost all modern programming languages and is usually referred to as regexes (plural of regex, short for Regular Expression). They provide a concise set of syntax to illustrate complex matches, one of which is usually translated into a background state machine for optimized performance.

If you have used regular expressions in other programming languages, then Scala should not surprise you. Let's look at an example.

/ / code-examples/Rounding/match-regex-script.scala val BookExtractorRE = "" Book: title= ([^,] +), scopyright authors = (. +) "" .r val MagazineExtractorRE = "Magazine: title= ([^,] +),".r val catalog = List (" Book: title=Programming Scala, authors=Dean Wampler, Alex Payne "," Magazine: title=The New Yorker, issue=January 2009 "," Book: title=War and Peace, authors=Leo Tolstoy "," Magazine: title=The Atlantic, issue=February 2009 " "BadData: text=Who put this here??") for (item println ("Book"+ title +", written by "+ authors) case MagazineExtractorRE (title, issue) = > println (" Magazine "" + title + ", issue" + issue) case entry = > println ("Unrecognized entry:" + entry)}}

We start with two regular expressions, one recording the information of the book and the other recording the magazine. Calling .r on a string turns it into a regular expression; we use the original (triple quotation mark) string to avoid many double escaped backslashes. If you think the .r conversion method of a string is not very clear, you can also define regular expressions by creating an instance of the Regex class, such as new Regex ("W").

Notice that each regular expression defines two capture groups, represented by parentheses. Each group captures a separate field on the record, such as the title or author of the book. The regular expression of Scala translates these capture groups into extractors. Each match sets the capture result to the corresponding field; if it is not captured, it is set to null.

What does this mean in practice? If the text supplied to the regular expression matches, case BookExtractorRE (title,authors) assigns the first capture group to title and the second to authors. We can use these values on the right side of the case statement, as we saw in the example above. The variable names title and author in the extractor are arbitrary; the matching results from the capture group are simply assigned from left to right, and you can call them anything you want.

This is a brief introduction to Scala regular expressions. The scala.util.matching.Regex class provides several convenient ways to find and replace matches in a string, whether all matches or the first one. Make good use of them.

We will not cover the details of writing regular expressions here. Scala's Regex class uses the corresponding platform's regular expression API (that is, Java, or. Net). Refer to these API documentation for more information, and there may be subtle differences between different languages.

Bind nested variables in Case sentences

Sometimes you want to be able to bind a variable to an object in a match while specifying matching criteria in nested objects. Let's modify the previous example to match the key-value pair of map. We take the same Person object as the value and the employee ID as the key. We will add an attribute-role to Person to specify which of the corresponding instances is in the type hierarchy.

/ code-examples/Rounding/match-deep-pair-script.scala class Role case object Manager extends Role case object Developer extends Role case class Person (name: String, age: Int, role: Role) val alice = new Person ("Alice", 25, Developer) val bob = new Person ("Bob", 32, Manager) val charlie = new Person ("Charlie", 32, Developer) for (item alice, 2-> bob, 3-> charlie) {item match {case (id, p @ Person (_, _) Manager)) = > format ("% s is overpaid.n", p) case (id, p @ Person (_, _)) = > format ("% s is underpaid.n", p)}}

This case object is the same as the single object we saw before, except for the behavior to which the special case class belongs. What we are most concerned about is p @ Person (...) nested in the case clause. We match specific types of Person objects in closed tuples. We also want to assign Person to a variable so that we can print it.

Person (Alice,25,Developer) is underpaid. Person (Bob,32,Manager) is overpaid. Person (Charlie,32,Developer) is underpaid.

If we use the matching criteria in Person itself, we can write p: Person directly. For example, the preceding match sentence can be written like this.

Item match {case (id, p: Person) = > p.role match {case Manager = > format ("% s is overpaid.n", p) case _ = > format ("% s is underpaid.n", p)}}

Idea p @ Person (...) Syntax gives us a way to flatten a nested match statement into a statement. This is similar to the way we use "capture groups" in regular expressions to extract the substrings we need instead of separating a string into several. You can use any method you prefer.

Use try,catch and finally statements

By using functional constructs and strongly typed features, Scala encourages programming styles that are less dependent on exceptions and exception handling. But when Scala interacts with Java, exceptions are common.

Be careful

Scala does not support exception checking (Checked Exception) like Java. Even if an exception is checked in Java, it is converted to an unchecked exception in Scala. There is also no throws clause in the method declaration. However, there is an @ throws annotation that can be used to interact with Java. See the annotations section in Chapter 13-Application Design.

Thanks to Scala, it actually treats exception handling as another form of pattern matching, allowing us to make smarter decisions when we encounter a variety of exceptions. Let's actually look at an example:

/ code-examples/Rounding/try-catch-script.scala import java.util.Calendar val then = null val now = Calendar.getInstance () try {now.compareTo (then)} catch {case e: NullPointerException = > println ("One was null!"); System.exit (- 1) case unknown = > println ("Unknown exception" + unknown); System.exit (- 1)} finally {println ("It all worked out.") System.exit (0)}

In the above example, we explicitly caught the NullPointerException exception, which is trying to throw a Calendar instance and null. We also define unknown as words that catch all exceptions, just in case. If we do not hard-code the program to fail, the finally block will be executed and the user will be told that everything is fine.

Be careful

You can use an underscore (Scala's standard wildcard) as a placeholder to catch any type of exception (not fooling you, it can match any case of a pattern matching expression). However, you can no longer access the exceptions in the following expression. You can also name the exception if necessary. For example, if you need to print out an exception message, as we did in the full-access case in the previous example, e or ex is a good name.

With pattern matching, handling of Scala exception operations should be easy for people who are familiar with Java,Ruby,Python and other major languages. And again, you can write throw new MyBadException (...) To throw an exception. That's all about anomalies.

Concluding remarks on pattern matching

Pattern matching is a powerful and elegant way to extract information from objects when used properly. Reviewing Chapter 1-from 0 to 60: an introduction to Scala, we emphasized the collaboration between pattern matching and polymorphism. Most of the time, you want to avoid "switch" statements when you know the class structure, because they must be changed at the same time as the structure changes.

In our painting executor (Actor) example, we used pattern matching to separate different message "types", but we used polymorphism to draw the graph we passed to it. We can modify the Shape inheritance structure, but the code in the Actor section does not need to be modified.

Pattern matching is also useful when you encounter design problems that need to extract data from within an object, but only in special cases. An unexpected result of the JavaBean specification is that it encourages people to expose fields inside objects through getters and setters. This should never be a default decision. Access to "state" information should be encapsulated and exposed only when it is logically meaningful to the type, consistent with its abstract observation.

On the contrary, consider using pattern matching when you need to get information in a controlled way. As we will see in the "Unapply" section of Chapter 6-Scala Advanced object-oriented programming, the pattern matching example we show uses predefined unapply methods to get information from the instance. These methods allow you to get this information without knowing the implementation details. In fact, the information returned by the unapply method may be a variation of the actual information in the instance.

Finally, when designing pattern matching instructions, be careful about your dependency on the default case. Under what circumstances does "none of the above match" is the correct answer? It may symbolize that the design needs to be perfected so that you know all possible matches more accurately. We will learn one of these techniques when we discuss the structure of the completion class in the "sealed class structure" of Chapter 7-Scala object system.

Enumerate

Remember our last example that involved many kinds of dogs? When thinking about the types of these programs, we may need a top-level Breed type to record a certain number of breeds. Such a type is called an enumerated type, and the values it contains are called enumerated values.

Although enumeration is a built-in support for many programming languages, Scala takes a different approach by implementing it as a class in the standard library. This means that there is no special enumeration syntax like Java and C # in Scala. Instead, you just define an object and let it inherit from the Enumeration class. Therefore, at the bytecode level, Scala enumerations have nothing to do with enumerations constructed in Java,C#.

Here's an example:

/ / code-examples/Rounding/enumeration-script.scala object Breed extends Enumeration {val doberman = Value ("Doberman Pinscher") val yorkie = Value ("Yorkshire Terrier") val scottie = Value ("Scottish Terrier") val dane = Value ("Great Dane") val portie = Value ("Portuguese Water Dog")} / / print a list of breeds and their IDs println ("IDtBreed") for (breed

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development