Scala入门指南与建议

最近在学习使用Scala语言做项目,感觉这门语言实在是太优美了!作为一个本科数学、研究生机器学习专业的混合人才(哈哈),这门语言真的是满足了普通计算机编程(告诉计算机怎么做)和函数式编程(告诉计算机做什么)的所有幻想。学了半个多月,根本停不下来!先来做个总结:

  1. 语法简洁,往往比Java少至少一半的代码量。比如:
    • 支持自动类型判断,可以省去很多类型标志。 e.g.  val x = 2
    • 用伴生对象来生成类,省去new的麻烦。e.g. val cat = Cat("Hello Ketty")
    • 不用return,直接把一个块(可以使if...else...块,for循环块等)的值返回。例如一行代码定义函数:def add(x: Int, y: Int): Int = x + y
    • 用()来统一函数的参数传递与带参类的构造。对类来说,这种写法其实是语法糖,因为中间有自动的转换机制,使得简洁的代码和底层实现可以分离。
    • 程序易读。对比C/C++、Python、Java,Scala是最符合人类理解的程序语言。
  2. 有几乎完全的函数式风格支持。
    • 函数和值一样,是第一等公民。函数也是值,值也可以作为函数。
    • 支持高阶函数、Curry化、lambda运算等函数运算概念。
    • 函数式风格要求函数尽量无副作用,这样一方面适合做单元测试来验证程序的正确性,另外很适合做并行计算!
  3. 可以满足大多数OOP编程需求。
    • 这里就不展开了。
  4. Scala兼具科学计算语言(matlab、R、Python等)的易读性与静态语言(C/C++、Java等)的高效率。

正是由于以上优点,我觉得Scala很有潜力成为下一门普及的编程语言。

另外,关于Scala学习曲线,我的建议是:

  1. 从网上各种博客大概了解Scala的特性,包括上面提到的几条。
  2. 看书:
    • 《Programming in Scala》和《Scala for the Impatient》交替看。前一本是Scala语言创建者写的,非常通俗易懂,包含了Scala的大多数“是什么”和“为什么”;后一本则是总结性的,把Scala的大多少“是什么”告诉你。
    • 《Scala in Depth》适合中等水平的Scala程序员阅读。(计划下一步看完)
  3. 做项目 / 开发程序。

最后,附上《Scala for the Impatient》(中文版《快学Scala》)的所有key notes 以及我做的部分课后题参考答案地址。如果有需要相关电子书的,可以给我发email。


《Scala for the Impatient》key notes

Chapter 1. The Basics
  • Using the Scala interpreter
  • Defining variables with val and var
  • Numeric types
  • Using operators and functions
  • Navigating Scaladoc
 
Chapter 2. Control Structures and Functions
  • An if expression has a value
  • A block has a value — the value of its last expression
  • The Scala for loop is like an "enhanced" Java for loop
  • Semicolons are (mostly) optional
  • The Void type is Unit
  • Avoid using return in a function
  • Beware of missing = in a function definition
  • Exceptions work just like in Java or C++, but you use a "pattern matching" syntax for catch 
  • Scala has no checked exceptions
 
Chapter 3. Working with Arrays
  • Use an Array if the length is fixed, and an ArrayBuffer if the length can vary
  • Don’t use new when supplying initial values
  • Use () to access elements
  • Use for (elem <- arr) to traverse the elements
  • Use for (elem <- arr if …) … yield … to transform into a new array
  • Scala and Java arrays are interoperable; with ArrayBuffer, use scala.collection.JavaConversions
 
Chapter 4. Maps and Tuples
  • Scala has a pleasant syntax for creating, querying, and traversing maps
  • You need to choose between mutable and immutable maps
  • By default, you get a hash map, but you can also get a tree map
  • You can easily convert between Scala and Java maps
  • Tuples are useful for aggregating values
 
Chapter 5. Classes
  • Fields in classes automatically come with getters and setters
  • You can replace a field with a custom getter / setter without changing the client of a class — that is the "uniform access principle"
  • Use the @BeanProperty annotation to generate the JavaBeans getXxx / setXxx methods
  • Every class has a primary constructor that is "interwoven" with the class definition. Its parameters turn into the fields of the class. The primary constructor excuses all statements in the body of the class
  • Auxiliary constructors are optional. That are called this.
 
Chapter 6. Objects
  • Use Objects for singletons and utility methods
  • A class can have a companion object with the same name.
  • Objects can extend classes or traits
  • The apply method of an object is usually used for constructing new instance of the companion class
  • To avoid the main method, use an object that extends that App trait
  • You can implement enumerations by extending the Enumeration object
 
Chapter 7. Packages and imports
  • Packages nest just like inner classes
  • Package paths are not absolute
  • A chain x.y.z in a package clause leaves the intermediate packages x and x.y invisible
  • Package statements without braces at the top of the file extend to the entire file
  • A package object can hold functions and variables
  • Import statements can import packages, classes, and objects
  • Import statements can be anywhere
  • Import statements can rename and hide menbers
  • java.lang, scala, and Predef are always imported
 
Chapter 8. Inheritance
  • The extends and final keywords are as in Java.
  • You must use override when you override a method
  • Only the primary constructors can all the primary superclass constructor
  • You can override fields
 
Chapter 9. Files and Regular Expressions
  • Source.fromFile(…).getLines.toArray yields all lines of a file
  • Source.fromFile(…).mkString yields the file contents as a string
  • To convert a string into a number, use the toInt or toDouble method
  • Use the Java PrintWriter to write text files
  • "regex".r is a Regex object
  • Use """…""" if your regular expression contains backslashes or quotes
  • If a regex pattern has groups, you can extract their contents using the syntax for (regex(var_1,…,var_n) <- string )
 
Chapter 10. Traits
  • A class can implement any number of traits
  • Traits can require that implementing classes have certain fields, methods, or superclasses
  • Unlike Java Interface, a Scala trait can provide implementations of methods and fields
  • When you layer multiple traits, the order matters — the trait whose methods execute first goes to the back
 
Chapter 11. Operators
  • Identifiers contain either alphanumeric or operator characters
  • Unary and binary operators are method calls
  • Operator precedence depends on the first character, associativity on the last
  • The apply and update methods are called when evaluating expr(args)
  • Extractors extract tuples or sequences of values from an input
 
Chapter 12. Higher-Order Functions
  • Functions are "first-class citizens" in Scala, just like numbers
  • You can create anonymous functions, usually to give them to other functions
  • A function argument specifies behavior that should be executed later
  • Many collection methods take function parameters, applying a function to the values of the collections
  • There are syntax shortcuts that allow you to express function parameters in a way that is short and easy to read
  • You can create functions that operate on the blocks of code and look much like the build-in control statement
 
Chapter 13. Collections
  • All collections extend the Iterable trait
  • The three major categories of collections are sequences, sets, and maps.
  • Scala has mutable and immutable versions of most collections
  • A Scala list is either empty, or it has a head and a tail which is again a list
  • Sets are unordered collections
  • Use a LinkedHashSet to retain the insertion order or a SortedSet to iterate in sorted order
  • + adds an elements to an unordered collection; +: and :+ prepend or append to a sequence; ++ concatenates two collections; - and -- remove elements
  • The Iterable and Seq traits have dozens of useful methods for common operations. Check them out before writing tedious loops.
  • Mapping, folding, and zipping are useful techniques for applying a function or operation to the elements of a collection
 
Chapter 14. Pattern Matching and Case Classes
  • The match expression is a better switch, without fall-through
  • If no pattern matches, a MatchError is thrown. Use the case _ pattern to avoid that
  • A pattern can include an arbitrary condition, called a guard
  • You can match on the type of an expression; prefer this over isInstanceOf / asInstanceOf
  • You can match patterns of arrays, tuples, and case classes, and bind parts of the pattern to variables
  • In a for expression, non matches are silently skipped
  • A case class is a class for which the compiler automatically produce the methods that are needed for pattern matching
  • The common superclass in a case class hierarchy should be sealed
  • Use the Option type for values that may or may not be present — it is safer than using null
 
Chapter 15. Annotations
  • You can annotate classes, methods, fields, local variables, parameters, expressions, type parameters and types.
  • With expressions and types, the annotation follows the annotated item
  • Annotation have the form @Annotation, @Annotation(value), or @Annotation(name1= value1, …)
  • @volatile, @transient, @strictfp, and @native generate the equivalent Java modifiers
  • Use @throws to generate Java-compatible throws specifications
  • The @tailrec annotation lets you verify that a recursive function uses tail call optimization
  • The assert function takes advantage of the @elidable annotation. You can optionally remove assertions from your Scala program
  • Use the @deprecated annotation to mark deprecated features.
 
Chapter 16. XML Processiong
  • XML literals <like> this </like> are of type NodeSeq
  • You can embed Scala code inside XML literals
  • The child property of a Node yield the child nodes
  • The attributes property of a Node yields a MetaData object containing the node attributes.
  • The \ and \\ operators carry out XPath-Like matches
  • You can match mode patterns with XML literals in case clauses
  • Use the RuleTransformer with RewriteRule instance to transform descendants of a node
  • The XML object interfaces with Java XML methods for loading and saving
  • The ConstructingParser is an alternate parser that preserves comments and CDATA sections
 
Chapter 17. Type parameters
  • Classes, traits, methods, and functions can have type parameters
  • Place the type parameters after the name, enclosed in square brackets
  • Type bounds have the form T <: UpperBound, T >: LowerBound, T <% ViewBound, T : ContextBound
  • You can restrict a method with a type constraint such as (implicit ev: T <: < UpperBound)
  • Use +T (covariance) to indicate that a generic type’s subtype relationship is in the same direction as the parameter T, or -T (contravariance) to indicate the reverse direction
  • Covariance is appropriate for parameters that denote outputs, such as elements in an immutable collection.
  • Contravariance is appropriate for parameters that denote inputs, such as function arguments.
 
Chapter 18. Advanced types
  • Singleton types are useful for method chaining and methods with object parameters
  • A type projection includes inner class instances for all objects of an outer class.
  • A type alias gives a short name for a type.
  • Structural types are equivalent to "duck typing"
  • Existential types provide the formalism for wildcard parameters of generic types.
  • Use a self type declaration to indicate that a trait requires another type.
  • The "cake pattern" uses self types to implement a dependency injection mechanism
  • An abstract type must be made concrete in a subclass
  • A higher-kinded type has a type parameter that is itself a parameterized type.
 
Chapter 19. Parsing
  • Alternatives, concatenation, options, and repetitions in a grammar turn into |, ~, opt, and rep in Scala combinator parsers.
  • With RegexParsers, literal strings and regular expressions match tokens.
  • Use ^^ to process parse results.
  • Use pattern matching in a function supplied to ^^ to take apart ~ result.
  • Use ~> and <~ to discard tokens that are no longer needed after matching.
  • The respell combinator handles the common case of repeated items with a seperator
  • A token-based parser is useful for paring languages with reserved words and operations. Be prepared to define your own lexer.
  • Parsers are functions that consume a reader and yield a parse result: success, failure, or error.
  • The Failure result provides the details for error reporting.
  • You may want to add failure clauses to your grammar to improve the quality of error message.
  • Thanks to operator symbols, implicit conversions, and pattern matching, the parser combinator library makes parser writing easy for anyone who understands context-free grammars. Even if you don’t feel the urge to write your own parsers, you may find this an interesting case study for an effective domain-specific language.
 
Chapter 20. Actors
  • Extend the Actor class and provide an act method for each other.
  • To send a message to an actor, use actor ! message.
  • Message sending is asynchronous: "send and forget."
  • To receive messages, an actor calls receive or react, usually in a loop.
  • The argument to receive / react is a block of case clauses (technically, a partial function)
  • Actors should never share state. Always send data using messages.
  • Don’t invoke methods on actors. Communicating by sending messages.
  • Avoid synchronous messaging — that is, unlink sending a message and waiting for a reply.
  • Actors can share threads by using react instead of receive, provided the control flow of the message handler is simple.
  • It is OK to let actors crash, provided you have other actors that monitor their demise. Use linking to set up monitoring relationships.
 
Chapter 21. Implicits
  • Implicit conversions are used to convert between types.
  • You must import implicit conversions so that they are in scope as single identifiers.
  • An implicit parameter list requests objects of a given type. They can be obtained from implicit objects that are defined as single identifiers in scope, or from the companion object of the desired type.
  • If an implicit parameter is a single-argument function, it is also used as an implicit conversion.
  • A context bound of a type parameter requires the existence of an implicit object of the given type.
  • If it is possible to locate an implicit object, this can serve as evidence that a type conversion is valid.
 
Chapter 22. Delimited Continuations
  • A continuation lets you go back to a previous point in a program.
  • You can capture a continuation in a shift block.
  • A contination function extends until the end of the enclosing reset block.
  • A continuation is the "reset of the computation" from the expression containing the shift to the end of the enclosing reset, with the shift replaced by a "hole"
  • When you call a continuation with an argument, the "hole" is set to the argument.
  • Code containing shift expressions is rewritten in "continuation-passing stype", or CPS, up to the enclosing reset.
  • A method containing a shift without a reset must be annotated with a CPS annotation.
  • Continuation can be used to turn a recursive visit of a tree structure into an iteration.
  • Continuations can undo the "inversion of control" in a web or GUI application.

部分《快学Scala》课后题答案(还在更新中):

https://github.com/fengfu-chris/Scala-for-the-Impatient-Exercises

上一篇:3.svn 配置版本库


下一篇:DataFrame 行列数据的筛选