Why learn Scala? You don’t need to be a data scientist or distributed computing expert to appreciate this object-oriented functional programming language. This practical book provides a comprehensive yet approachable introduction to the language, complete with syntax diagrams, examples, and exercises. You’ll start with Scala's core types and syntax before diving into higher-order functions and immutable data structures.
Author Jason Swartz demonstrates why Scala’s concise and expressive syntax make it an ideal language for Ruby or Python developers who want to improve their craft, while its type safety and performance ensures that it’s stable and fast enough for any application.
Learn about the core data types, literals, values, and variables
Discover how to think and write in expressions, the foundation for Scala's syntax
Write higher-order functions that accept or return other functions
Become familiar with immutable data structures and easily transform them with type-safe and declarative operations
Create custom infix operators to simplify existing operations or even to start your own domain-specific language
Build classes that compose one or more traits for full reusability, or create new functionality by mixing them in at instantiation
I hope you’ve seen how using the Scala REPL to evaluate and experiment with code provides an enriched learning environment for this programming language. As you continue through this book, keep the REPL open and use it to validate everything you learn. The code samples throughout the book are presented as raw captures of REPL sessions to both validate that they work and what they print out, and also to make it easier for you to replicate them in your own REPL session.
Even better, modify and rework code examples until they break. Scala is a compiled, statically typed language, so the REPL (which compiles a line after you hit Return) will let you know immediately if you have entered incorrect Scala code or not. This will help you pick up the language more quickly and better understand the limits of its syntax and features.
Exercises
Although println() is a good way to print a string, can you find a way to print a string without println? Also, what kinds of numbers, strings, and other data does the REPL support?
In the Scala REPL, convert the temperature value of 22.5 Centigrade to Fahrenheit. The conversion formula is cToF(x) = (x * 9/5) + 32.
Take the result from exercise 2, halve it, and convert it back to Centigrade. You can use the generated constant variable (e.g., “res0”) instead of copying and pasting the value yourself.
The REPL can load and interpret Scala code from an external file with the :load <file> command. Create a new file named Hello.scalaand add a command that will print a greeting, then execute it from the REPL.
Another way to load external Scala code is to paste it into the REPL in “raw” mode, where the code is compiled as if it were actually in a proper source file. To do this, type :paste -raw, hit Return, and then paste the contents of your source file from exercise 4. After exiting “paste” mode you should see the greeting.
This may be a challenging chapter to see through to the end, because you had to read all about types and data without learning how to do real programming in Scala yet. I’m glad you did.
What was the oddest or most-unexpected part of this chapter? The use of keywords to announce value and variable definition? The reversed manner (if you’re coming from Java) of defining a variable’s name before its type? The idea that much of your code can use fixed, nonreassignable values instead of (variable) variables?
If these ideas were hard to take, the good news is that, as you gain experience in Scala developemnt, they will become quite normal. Eventually they may even seem to be obvious choices for a well-designed functional programming language.
At this point you should know how to define your own values and variables, although we haven’t yet learned where to come up with useful data to store in them. In the next chapter you will study ways to derive and calculate this data using logical structures known as expressions.
Exercises
Write a new Centigrade-to-Fahrenheit conversion (using the formula (x * 9/5) + 32), saving each step of the conversion into separate values. What do you expect the type of each value will be?
Modify the Centigrade-to-Fahrenheit formula to return an integer instead of a floating-point number.
Using the input value 2.7255, generate the string “You owe $2.73.” Is this doable with string interpolation?
Convert the number 128 to a Char, a String, a Double, and then back to an Int. Do you expect the original amount to be retained? Do you need any special conversion functions for this?
Using the input string “Frank,123 Main,925-555-1943,95122” and regular expression matching, retrieve the telephone number. Can you convert each part of the telephone number to its own integer value? How would you store this in a tuple?
We covered if/else conditions, pattern matching, and loops in detail in this chapter. These structures provide a solid basis for writing core logic in Scala.
However, these three (or two) structures are just as important to learning Scala development as learning about the fundamentals of expressions. The namesake of this chapter—expressions and their return values—are the real core building block of any application. Expressions themselves may seem to be an obvious concept, and devoting an entire chapter to them has the appearance of being overly generous to the topic. The reason I have devoted a chapter to them is that learning to work in terms of expressions is a useful and valuable skill. You should consider expressions when writing code, and even structure your applications around them. Some important principles to keep in mind when writing expressions are (1) how you will organize your code as expressions, (2) how your expressions will derive a return value, and (3) what you will do with that return value.
Expressions, in addition to being a foundation for your code organization, are also a foundation for Scala’s syntax. In this chapter we have defined if/else conditions, pattern matching, and loops in terms of how they are structured around expressions. In the next chapter we will continue this practice by introducing functions as named, reusable expressions and defining them as such. Future chapters will continue this trend of defining concepts and structures in terms of expressions. Thus, understanding the basic nature and syntax of expressions and expression blocks is a crucial key to picking up the syntax for the rest of the language.
Exercises
While the Scala REPL provides an excellent venue for experimenting with the language’s features, writing more than a line or two of code in it can be challenging. Because you’ll need to start working with more than a few lines of code, it’s time to start working in standalone Scala source files.
The scala command, which launches the Scala REPL, can also be used to evaluate and execute Scala source files:
$ scala <source file>
复制代码
To test this out, create a new file titled Hello.scala with the following contents:
println("Hello, World")
复制代码
Then execute it with the scala command:
$ scala Hello.scala
Hello, World
$
复制代码
You should see the result (“Hello, World”) printed on the next line.
An alternate way to execute external Scala files is with the :load command in the Scala REPL. This is useful if you want to stay in the Scala REPL while still using a text editor or IDE to edit your code.
To test this out, in the same directory you created the Hello.scala file, start the Scala REPL and run :load Hello.scala:
Because most of the language’s logical structures were covered in Chapter 3, it made sense to focus this, the chapter following expressions, on how to organize and reuse them as functions. Indeed, while a function’s name, input parameters, and return value type are important parts of a function’s definition, the actual contents of a function are one big expression.
An entire chapter about functions should be no less than expected from a book itself devoted to a functional programming language. However, though you just finished an entire chapter about functions, you have not yet learned everything there is to know about functions. Namely, that in Scala you can treat your functions as data and pass them into other functions to invoke.
This concept of functions as data, with their own literals and types, brings functions up to par with other forms as data. You’ll learn all about how functions can receive the same treatment as other data types, making them “first-class” citizens of the language, in the next chapter.
Exercises
Write a function that computes the area of a circle given its radius.
Provide an alternate form of the function in exercise 1 that takes the radius as a String. What happens if your function is invoked with an empty String ?
Write a recursive function that prints the values from 5 to 50 by fives, without using for or while loops. Can you make it tail-recursive?
Write a function that takes a milliseconds value and returns a string describing the value in days, hours, minutes, and seconds. What’s the optimal type for the input value?
Write a function that calculates the first value raised to the exponent of the second value. Try writing this first using math.pow, then with your own calculation. Did you implement it with variables? Is there a solution available that only uses immutable data? Did you choose a numeric type that is large enough for your uses?
Write a function that calculates the difference between a pair of 2D points (x and y) and returns the result as a point. Hint: this would be a good use for tuples (see Tuples).
Write a function that takes a 2-sized tuple and returns it with the Int value (if included) in the first position. Hint: this would be a good use for type parameters and the isInstanceOf type operation.
Write a function that takes a 3-sized tuple and returns a 6-sized tuple, with each original parameter followed by its String representation. For example, invoking the function with (true, 22.25, "yes") should return (true, "true", 22.5, "22.5", "yes", "yes"). Can you ensure that tuples of all possible types are compatible with your function? When you invoke this function, can you do so with explicit types not only in the function result but in the value that you use to store the result?
Scala treats functions as first-class data types, as demonstrated throughout this chapter and supported by the notions of higher-order functions, function literals, and function types. While simply stated, until you have some experience working with first-class functions you may find the concept a difficult one to understand. If you haven’t already done so, I highly recommend trying out the code samples and experimenting with writing your own first-class function-based code. And then, after you have become familiar with storing functions as data and using them to invoke higher-order functions, you’ll find the following exercises will help to increase your comfort level with this challenging topic.
The real beauty and utility of higher-order functions, however, cannot be demonstrated with the data types we have thus far learned. To really demonstrate them we will need to learn a critical component of writing any kind of useful and data-driven code. I’m talking about collections, data structures that scale from zero to many elements and make it possible to collect multiple values of a given type. From lists to maps, Scala not only supports the data structures that you’re well familiar with, but provides ample use of higher-order functions to maximize your productivity. We’ll cover not only creating and iterating through collections, but how you’ll use map(), reduce(), and filter()to manage them with amazingly expressive code.
From this point forward you can expect to see first-class functions and higher-order functions play a prominent role in code examples and exercises. Whether demonstrated with the data types we have learned thus far or with the higher-order function-based collections library, these are the shining stars of the Scala language.
Exercises
Write a function literal that takes two integers and returns the higher number. Then write a higher-order function that takes a 3-sized tuple of integers plus this function literal, and uses it to return the maximum value in the tuple.
The library function util.Random.nextInt returns a random integer. Use it to invoke the “max” function with two random integers plus a function that returns the larger of two given integers. Do the same with a function that returns the smaller of two given integers, and then a function that returns the second integer every time.
Write a higher-order function that takes an integer and returns a function. The returned function should take a single integer argument (say, “x”) and return the product of x and the integer passed to the higher-order function.
Let’s say that you happened to run across this function while reviewing another developer’s code:
def fzero[A](x: A)(f: A => Unit): A = { f(x); x }
复制代码
What does this function accomplish? Can you give an example of how you might invoke it?
There’s a function named “square” that you would like to store in a function value. Is this the right way to do it? How else can you store a function in a value?
def square(m: Double) = m * m
val sq = square
复制代码
Write a function called “conditional” that takes a value x and two functions, p and f, and returns a value of the same type as x. The p function is a predicate, taking the value x and returning a Boolean b. The f function also takes the value x and returns a new value of the same type. Your “conditional” function should only invoke the function f(x) if p(x) is true, and otherwise return x. How many type parameters will the “conditional” function require?
Do you recall the “typesafe” challenge from the exercises in Chapter 3? There is a popular coding interview question I’ll call “typesafe,” in which the numbers 1-100 must be printed one per line. The catch is that multiples of 3 must replace the number with the word “type,” while multiples of 5 must replace the number with the word “safe.” Of course, multiples of 15 must print “typesafe.”
Use the “conditional” function from exercise 6 to implement this challenge.
Would your solution be shorter if the return type of “conditional” did not match the type of the parameter x? Experiment with an altered version of the “conditional” function that works better with this challenge.
Working with collections, whether creating, mapping, filtering, or performing other operations, is a major component of software development. And lists, maps, and sets, some of the main building blocks for scalable data structures, are included as part of the default libraries for Java, Ruby, Python, PHP, and C++. What sets Scala’s collections library apart from the others is its core support for immutable data structures and higher-order operations.
The core data structures in Scala, List, Map, and Set, are immutable. They cannot be resized, nor can their contents be swapped out. As a way of giving precedence over mutable collections, their package (collection.immutable) is automatically imported into Scala namespaces by default. This precedence aims to steer developers toward the immutable collections and immutable data in general, a “best practice” in functional programming circles. This is not to say that mutable collections are less powerful or less capable than immutable ones. Scala’s mutable collections have all the same features as the immutable ones and also support a range of modification operations. We’ll learn about mutable collections and how to convert mutable to immutable ones (and vice versa) in the next chapter.
The ability to take a collection and iterate or map it with an anonymous function is common to many languages, including Ruby and Python. However, the ability to do so while ensuring the type requirements of both the collection and the input and return types of the anonymous functions is relatively uncommon. Collections with type-safe higher-order functions support a declarative programming style, the ability to create expressive code, and very few runtime type conversion errors. This powerful combination of features helps to set the Scala collections library apart from those available in other languages and frameworks and provides a fairly large productivity boost to its users. In addition, Scala collections are monadic, supporting the ability to chain operations together in a high-level, type-safe manner. We’ll learn about monadic collections as well in the next chapter.
Exercises
Do you recall the suggestion I previously made (see Exercises) to switch your development environment from inside-the-REPL to an external Scala source file? If you haven’t made the switch yet, you’ll find working on these exercises in the REPL to be downright impractical given their size and complexity.
I also recommend working on these exercises using a professional IDE such as IntelliJ IDEA CE or the Eclipse-based Scala IDE. You’ll gain instant feedback about whether code is compilable and get code completion and documentation for Scala library functions. There are also plug-ins for simpler editing environments like Sublime Text, VIM, and Emacs that enable this functionality, but if you’re getting started with Scala a full-fledged IDE will probably be easier and quicker to use.
The exercises in this section will help you become familiar with the core collections and operations we have studied in this chapter. I recommend spending time to not only write the most basic solution, but to find alternate methods for each implementation. This will help you become familiar with the subtle differences between similar functions such as fold and reduce, or head and slice, in addition to giving you the tools to bypass these functions and develop your own solutions.
Create a list of the first 20 odd Long numbers. Can you create this with a for-loop, with the filter operation, and with the map operation? What’s the most efficient and expressive way to write this?
Write a function titled “factors” that takes a number and returns a list of its factors, other than 1 and the number itself. For example,factors(15) should return List(3, 5).
Then write a new function that applies “factors” to a list of numbers. Try using the list of Long numbers you generated in exercise 1. For example, executing this function with List(9, 11, 13, 15) should return List(3, 3, 5), because the factor of 9 is 3 while the factors of 15 are 3 again and 5. Is this a good place to use map and flatten? Or would a for-loop be a better fit?
Write a function, first[A](items: List[A], count: Int): List[A], that returns the first x number of items in a given list. For example,first(List('a','t','o'), 2) should return List('a','t'). You could make this a one-liner by invoking one of the built-in list operations that already performs this task, or (preferably) implement your own solution. Can you do so with a for-loop? With foldLeft? With a recursive function that only accesses head and tail?
Write a function that takes a list of strings and returns the longest string in the list. Can you avoid using mutable variables here? This is an excellent candidate for the list-folding operations (Table 6-5) we studied. Can you implement this with both fold and reduce? Would your function be more useful if it took a function parameter that compared two strings and returned the preferred one? How about if this function was applicable to generic lists, i.e., lists of any type?
Write a function that reverses a list. Can you write this as a recursive function? This may be a good place for a match expression.
Write a function that takes a List[String] and returns a (List[String],List[String]), a tuple of string lists. The first list should be items in the original list that are palindromes (written the same forward and backward, like “racecar”). The second list in the tuple should be all of the remaining items from the original list. You can implement this easily with partition, but are there other operations you could use instead?
The last exercise in this chapter is a multipart problem. We’ll be reading and processing a forecast from the excellent and free OpenWeatherMap API.
To read content from the URL we’ll use the Scala library operation io.Source.+fromURL(url: String), which returns an +io.Sourceinstance. Then we’ll reduce the source to a collection of individual lines using the getLines.toList operation. Here is an example of usingio.Source to read content from a URL, separate it into lines, and return the result as a list of strings:
scala> val l: List[String] = io.Source.fromURL(url).getLines.toList
复制代码
Here is the URL we will use to retrieve the weather forecast, in XML format:
Go ahead and read this URL into a list of strings. Once you have it, print out the first line to verify you’ve captured an XML file. The result should look pretty much like this:
scala> println( l(0) )
<?xml version="1.0" encoding="utf-8"?>
复制代码
If you don’t see an XML header, make sure that your URL is correct and your Internet connection is up.
Let’s begin working with this List[String] containing the XML document.
To make doubly sure we have the right content, print out the top 10 lines of the file. This should be a one-liner.
The forecast’s city’s name is there in the first 10 lines. Grab it from the correct line and print out its XML element. Then extract the city name and country code from their XML elements and print them out together (e.g., “Paris, FR”). This is a good place to use regular expressions to extract the text from XML tags (see Regular expressions).
If you don’t want to use regular expression capturing groups, you could instead use the replaceAll() operation on strings to remove the text surrounding the city name and country name.
How many forecast segments are there? What is the shortest expression you can write to count the segments?
The “symbol” XML element in each forecast segment includes a description of the weather forecast. Extract this element in the same way you extracted the city name and country code. Try iterating through the forecasts, printing out the description.
Then create an informal weather report by printing out the weather descriptions over the next 12 hours (not including the XML elements).
Let’s find out what descriptions are used in this forecast. Print a sorted listing of all of these descriptions in the forecast, with duplicate entries removed.
These descriptions may be useful later. Included in the “symbol” XML element is an attribute containing the symbol number. Create aMap from the symbol number to the description. Verify this is accurate by manually accessing symbol values from the forecast and checking that the description matches the XML document.
What are the high and low temperatures over the next 24 hours?
What is the average temperature in this weather forecast? You can use the “value” attribute in the temperature element to calculate this value.
Now that you have solved the exercises, are there simpler or shorter solutions than the ones you chose? Did you prefer infix dot notation or infix operator notation? Was using for..yield easier than higher-order operations like map and filter?
This is a good place to rework some of your solutions to really find your favored coding style, which is often the intersection between ease of writing, ease of reading, and expressiveness.
Mutable collections, well known and available in most programming languages, have the best of both worlds in Scala. They can be used as incremental buffers to expand collections one item at a time using buffers, builders, or other approaches, but also support the wide variety of operations available to immutable collections.
And collections are, especially as Scala broadly defines them, more than simple containers for application data. Monadic collections provide type-safe chainable operations and management for sensitive and complex situations such as missing data, error conditions, and concurrent processing.
In Scala, immutable, mutable, and monadic collections are indispensable building blocks and foundations for safe and expressive software development. They are ubiquitious in Scala code, and are generally applicable to a wide range of uses.
By learning and becoming familiar with the core operations of Iterable, and with the safe operation chaining of monadic collections, you can better leverage them as a core foundation for your applications in Scala.
This chapter concludes the Scala instructions for Part 1. In Part 2 we will cover object-oriented Scala, a core feature of this programming language, while continuing to use what we have learned thus far.
Exercises
The Fibonacci series starts with the numbers “1, 1” and then computes each successive element as the sum of the previous two elements. We’ll use this series to get familiarized with the collections in this chapter.
Write a function that returns a list of the first x elements in the Fibonacci series Can you write this with a Buffer? Would a Builder be appropriate here?
Write a new Fibonacci function that adds new Fibonacci numbers to an existing list of numbers. It should take a list of numbers (List[Int]) and the count of new elements to add and return a new list (List[Int]). Although the input list and returned lists are immutable, you should be able to use a mutable list inside your function. Can you also write this function using only immutable lists? Which version, using mutable versus immutable collections, is more appropriate and readable?
The Stream collection is a great solution for creating a Fibonacci series. Create a stream that will generate a Fibonacci series. Use it to print out the first 100 elements in the series, in a formatted report of 10 comma-delimited elements per line.
Write a function that takes an element in the Fibonacci series and returns the following element in the series. For example,fibNext(8) should return 13. How will you handle invalid input such as fixNext(9)? What are your options for conveying the lack of a return value to callers?
In the example for Array collections (see Arrays) we used the java.io.File(<path>).listFiles operation to return an array of files in the current directory. Write a function that does the same thing for a directory, and converts each entry into its String representation using the toString method. Filter out any dot-files (files that begin with the . character) and print the rest of the files separated by a semicolon (;). Test this out in a directory on your computer that has a significant number of files.
Take the file listing from exercise 2 and print a report showing each letter in the alphabet followed by the number of files that start with that letter.
Write a function to return the product of two numbers that are each specified as a String, not a numeric type. Will you support both integers and floating-point numbers? How will you convey if either or both of the inputs are invalid? Can you handle the converted numbers using a match expression? How about with a for-loop?
Write a function to safely wrap calls to the JVM library method System.getProperty(<String>), avoiding raised exceptions or null results.System.getProperty(<String>) returns a JVM environment property value given the property’s name. For example,System.getProperty("java.home") will return the path to the currently running Java instance, while System. getProperty("user.timezone")returns the time zone property from the operating system. This method can be dangerous to use, however, because it may throw exceptions or return null for invalid inputs. Try invoking System.getProperty("") or System.getProperty("blah") from the Scala REPL to see how it responds.
Experienced Scala developers build their own libraries of functions that wrap unsafe code with Scala’s monadic collections. Your function should simply pass its input to the method and ensure that exceptions and null values are safely handled and filtered. Call your function with the example property names used here, including the valid and invalid ones, to verify that it never raises exceptions or returns null results.
Write a function that reports recent GitHub commits for a project. GitHub provides an RSS feed of recent commits for a given user, repository, and branch, containing XML that you can parse out with regular expressions. Your function should take the user, repository, and branch, read and parse the RSS feed, and then print out the commit information. This should include the date, title, and author of each commit.
You can use the following RSS URL to retrieve recent commits for a given repository and branch:
Working with the XML will be a bit tricky. You may want to use text.split(<token>) to split the text into the separate <entry>components, and then use regular expression capture groups (see Regular expressions) to parse out the <title> and other elements. You could also just try iterating through all the lines of the XML file, adding elements to a buffer as you find them, and then converting that to a new list.
Once you have completed this exercise (and there is a lot to do here), here are some additional features worth investigating:
Move the user, repo, and branch parameters into a tuple parameter.
Following exercise (a), have the function take a list of GitHub projects and print a report of each one’s commits, in order of specified project.
Following exercise (b), retrieve all of the projects, commit data concurrently using futures, await the result (no more than 5 seconds), and then print a commit report for each project, in order of project specified.
Following exercise (c), mix the commits together and sort by commit date, then print your report with an additional “repo” column.
These additional features will take some time to implement, but are definitely worthwhile for learning and improving your Scala development skills.
Once you have finished these features, test out your commit report using entries from the following projects:
These features are all active (as of 2014), so you should see an interesting mix of commit activity data in your report. It’s worthwhile to browse the repositories for these core open source Scala projects, or at least their documentation, to understand some of the excellent work being done.
Write a command-line script to call your GitHub commit report function from exercise 6 and print out the results. This will require a Unix shell; if you are on a Windows system you will need a compatible Unix environment such as Cygwin or Virtualbox (running a Unix virtual machine). You’ll also need to install SBT (Simple Build Tool), a build tool that supports dependency management and plug-ins and is commonly used by Scala projects. You can download SBT from http://www.scala-sbt.org/ for any environment, including an MSI Windows Installer version. SBT is also available from popular package managers. If you are using Homebrew on OS X you can install it with brew install sbt.
1) Write a new centigrade-to-fahrenheit conversion (using the formula (x * 9/5) + 32), saving each step of the conversion into separate values. What do you expect the type of each value will be?
Answer
Let’s pick a centigrade temperature at random, say 7 degrees. For optimal accuracy we’ll use 5.0, a floating-point number, to ensure the remainder of the division is preserved.
scala> val celsius = 7
celsius: Int = 7
scala> val fahr1 = celsius * 9
fahr1: Int = 63
scala> val fahr2 = fahr1 / 5.0
fahr2: Double = 12.6
scala> val fahrenheit = fahr2 + 32
fahrenheit: Double = 44.6
We now have named values for each step of the calculation, with a final answer of 44.6 degrees fahrenheit.
2) Modify the centigrade-to-fahrenheit formula to return an integer instead of a floating-point number.
Answer
The "5.0" floating-point number value resulted in the final result having the same type. To return an integer, we can switch the one floating-point number to an integer.
scala> val fahr2 = fahr1 / 5
fahr2: Int = 12
scala> val fahrenheit = fahr2 + 32
fahrenheit: Int = 44
The result, 44, is pretty darn close to the value calculated with a floating-point divisor, 44.6.
3) Using the input value 2.7255, generate the string "You owe $2.73 dollars". Is this doable with string interpolation?
Answer
String interpolation, the act of inserting placeholders for named values, is the right solution here. It will let us use printf formatting to convert the input value down to only two decimal values. The printf format for doing so is "%.2f", which specifies that exactly two of the most significant decimal digits will be printed.
The really hard part is getting the dollar sign that prefixes the amount to print, as it is right up against the dollar sign we’ll need to trigger string interpolation. Fortunately a double dollar sign will be recognized as a request to print a literal dollar sign, which we can follow with another dollar sign to begin interpolation.
scala> val amount = 2.7255
amount: Double = 2.7255
scala> val s = f"You owe $$$amount%.2f dollars"
s: String = You owe $2.73 dollars
4) Is there a simpler way to write the following?
val flag: Boolean = false
val result: Boolean = (flag == false)
Answer
This was a deliberately easy question, written with the goal to prod you to look for ways to reduce unnecessary code (even in the simple value assignments given here). A correct answer is that both the explicit types and the lengthy comparison can be simplified, requiring one to check both sides of the equation for code that can be removed.
scala> val flag = false
flag: Boolean = false
scala> val result = !flag
result: Boolean = true
5) Convert the number 128 to a Char, a String, a Double, and then back to an Int. Do you expect the original amount to be retained? Do you need any special conversion functions for this?
Answer
You’ll need a host of conversion functions for this one! If you’re unsure of the exact function name, you can find them in the Scaladoc pages for the source type. You can also try the REPL’s tab-based. code completion feature. Go ahead and type "128." followed by a tab to see the available functions for that integer.
scala> val orig = 128
orig: Int = 128
scala> val c: Char = orig.toChar
c: Char = �
scala> val s: String = c.toString
s: String = �
scala> val d: Double = s(0).toDouble
d: Double = 128.0
scala> val i: Int = d.toInt
i: Int = 128
6) Using the input string "Frank,123 Main,925-555-1943,95122" and regular expression matching, retrieve the telephone number. Can you convert each part of the telephone number to its own integer value? How would you store this in a tuple?
Answer
Let’s break this into separate steps to keep the parsing code simple. First, we’ll extract the phone number into three separate strings.
scala> val s = "Frank,123 Main,925-555-1943,95122"
s: String = Frank,123 Main,925-555-1943,95122
scala> val p = """.*,(\d{3})-(\d{3})-(\d{4}),.*""".r
3.1) Given a string name, write a match expression that will return the same string if non-empty, or else the string "n/a" if it is empty.
Answer
You could use a pattern guard here and check if the size of the string is zero or non-zero. However, it’s easier to just match based on an empty string.