A cheat sheet for Scala’s DSL-friendly features(速查表)

DSLs IN ACTION书中的附录:

A cheat sheet for Scala’s DSL-friendly features

Scala的DSL特色代码速查表


DSL-friendly features of Scala

Scala is an object-functional language that runs on the JVM. It has great interoperability with Java by virtue of having the same object model (and more). Scala has a nice, concise syntax, offers type inference, and a whole bunch of mechanisms for designing abstractions based on a combination of OO and functional paradigms.

Scala是运行在JVM下的一门面向对象语言。它与Java有很好的互操作性,因为有同样的对象模型(和其他很多方面)。Scala有好的,简明的语法,提供的类型推断, 为了抽象设计的一大堆 基于面向对象和函数式范例的机制

Class-based OOP

Scala is OO. You can define classes that have instance variables and methods.
But besides being a class, a Scala abstraction can be of many other types, each with its own set of features and applicability.
We’re going to look at most of them in this appendix.
When you design a DSL using Scala, it’s common to model the entities of your domain as classes or as any of the other ways to group related functionalities.
For details about class definition syntax, refer to [1] in section D.2.

  class Account(val no: Int, val name: String) {
    def balance: Int = {
    //.. implementation
    }
    //..
  }

A class definition can take parameters.
In this snippet, val implies that no and name are immutable and cannot be reassigned.
balanceis a method that you can define. It doesn’t take any argument and returns anInt.

Case classes (样例类)

You can add the word case before a class definition and get a lot of mileage out of the abstraction that the compiler generates.

It’s called a case class in Scala. For a case class, the compiler automatically does the following:
  • Converts the constructor arguments into
immutable vals. You can explicitly specify varto decide otherwise.
  • Implements equals,hashCode, and
toString methods to the class.
  • Lets you invoke a shorthand notation for the
constructor. You don’t need to specify the keywordnew while instantiating an object of the class.
The compiler gives you a companion object that contains the apply() constructor and an extractor on the constructor arguments.

Case classes are also useful for pattern matching.
They’re the most idiomatic way to implement algebraic data types in Scala.
Because of the built-in features of immutability that case classes offer, they’re often used to build immutable value objects when designing DSLs.

  abstract class Term
  case class Var(name: String) extends Term
  case class Fun(arg: String, body: Term) extends Term

For this case class definition, you can instantiate as val p = Var("p") , without having to explicitly specify new.

Traits (特质)

Traits are yet another way to specify abstractions in Scala.
They’re similar to Java interfaces in that you can leave out the  implementation for concrete classes.
But unlike interfaces, you can specify partial implementations of some methods in a trait.
Traits offer a way to implement mixins in Scala and can also be used to design the correct way to use multiple inheritance.

  trait Audit {
    def record_trail {
    //... implementation
    }
    def view_trail // open
  }
  class SavingsAccount extends Account with Audit {
  //...
  }

Traits are a great way to design open reusable abstractions without committing to a specific implementation.
Note how in this definition, the method view_trail is kept open for implementation by the abstraction that mixes in the trait
.

Higher-order functions & closures (高阶函数 & 闭包)

In Scala, functions are first-class values, and you can pass a function as an argument to yet another function.
You can also have a function return another function.
Functions as first-class values give Scala the main power for functional programming.
Higher-order functions make code less verbose and express the correct verb semantics of your DSL.
Closures let you write fewer classes and objects and more functional artifacts.


  val hasLower = bookTitle.exists(_.isLowerCase)
 def foo(bar: (Int, Int)=>Int) {
  //...
 }
In the first example, the method exists takes a function as an argument that it applies to each
character of the string.
In Java, this would’ve been way more verbose.
The second example shows the literal syntax of a function in Scala.

Pattern matching  (模式匹配)

Like all functional programming languages, Scala has pattern matching.
You can match arbitrary expressions with a first-match-wins policy in Scala.
Case classes and pattern matching are a potent combination for implementing functional idioms in Scala.
You can implement an extensible Visitor pattern using case classes.
As you see in chapter 6, pattern matching plays an important role in making expressive business rules.

  def foo(i: Int) = i match {
  case 10 => //..
  case 12 => //..
  case _ =>
 }
The previous rendering is a more concise Scala version of Java’s switch/case statement. But pattern matching has many other uses.
  val obj = doStuff()
  var cast:Foo = obj match {
    case x:Foo => x
    case _ => null
  }
The earlier example is a more idiomatic way of implementing an instanceOf check used in Java.
  trait Account
  case class Checking(no: Int) extends Account
  case class Savings(no: Int, rate: Double) extends Account
    def process(acc: Account) = acc match {
      case Checking(no) => // do stuff
      case Savings(no, rt) => // do stuff
    }
Case classes can be used directly for pattern matching.
Note that earlier I said that case classes implement extractors by default.

Objects as modules (对象)

Objects define executable modules in Scala.
After you define abstractions using classes and traits, you can compose them together into
a concrete abstraction using the object syntax.
Object syntax is the closest approximation of statics that are used in Java.
  object RuleComponent extends Rule with CountryLocale with Calendar {
   //..
 }

RuleComponent is a singleton object created out of the specified abstractions



Implicit arguments (隐含变量)

You can leave out the last argument of a function by declaring it to be implicit.
(方法最后的变量可以被忽略,声明它作为一个隐含的变量。)
The compiler will look for a matching argument from the enclosing scope of the function.
(编译器
从方法域内找到一个匹配的变量。)
  def shout(at: String)(implicit curse: String) {
   println("hey: " + at + " " + curse)
 }
 implicit val curse = "Damn! "
 shout("Rob")

The compiler will complain if it can’t find a matching argument from the enclosing scope.
(如果域内没有匹配的变量
,编译器会抛出异常。)

Implicit type conversions (aka Pimp My Library) (隐式类型转化)

You can extend existing libraries without making any changes to them by using implicit type conversions.
(可以通过使用隐式类型转换扩展存在的库。)
It works much like Ruby monkey patching, but it’s controlled within the lexical scope.
Martin Odersky named this the Pimp My Library pattern (see [2] in section D.2).
The implicit conversion function is automatically applied by the compiler.
(编译器自动应用这种隐式转换方法。)
This helps you make your legacy abstractions smart with improved APIs.

 class RichArray[T](value: Array[T]) {
   def append(other: Array[T]): Array[T] = {
   //.. implementation
   }
 }
 implicit def enrichArray[T](xs: Array[T]) = new RichArray[T]

The implicit definition of enrichArray serves as the conversion function from Array to RichArray.
(隐式定义
enrichArray的作用是把Array转换成RichArray的方法.)

Partial functions (偏函数)

A partial function is one that's defined only for a set of values of its arguments.
偏函数只是定义变量中的一系列值。(偏函数只对变量中一部分值有作业。)
Partial functions in Scala are modeled as blocks of pattern-matching case statements.
(Scala中的偏函数是一个模式匹配块。)
PartialFunctions are used idiomatically to define the message receive loop in Scala actors.
(在Akka中,偏函数通常惯用的去定义消息接收循环。)

  val onlyTrue: PartialFunction[Boolean, Int] = {
   case true => 100
 }

onlyTrue is a PartialFunction that’s defined for a limited domain.
It’s defined only for the Boolean value true.
The PartialFunction trait contains a method isDefinedAt that returns true for the domain values for which the PartialFunction is defined.
Here’s an example:
 scala> onlyTrue isDefinedAt(true)
 res1: Boolean = true
 scala> onlyTrue isDefinedAt(false)
 res2: Boolean = false

Generics & type parameters (泛型 & 类型变量)

Scala offers type parameters that you specify as part of your class and method declarations.
(Scala提供类型变量作为class和method声明的一部分。)
You can also specify explicit constraints on these types that your abstraction will honor.
(可以指定这些类型的明确约束,你的抽象会兑现。)
You get an automatic level of constraint checking by the compiler without having to write a single line of validation logic.
(可以通过编译器获得自动水平的约束检测,而不需要写一行验证逻辑。)
With Scala, you can abstract many of your DSL constraints within the type system
.
(通过Scala,在类型系统中你可以抽象出许多DSL约束。)
  class Trade[Account <: TradingAccount](account: Account) {
   //..
 }

In this class definition, you won’t be able to create an instance of  Trade with an account that doesn’t satisfy the specified constraint.
(在这个class定义中,你不能创建这样一个Trade实例-使用一个
不能让指定的约束满意的account。)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值