请选择 进入手机版 | 继续访问电脑版
楼主: Lisrelchen
2041 16

Programming Scala [推广有奖]

Lisrelchen 发表于 2016-4-3 23:59:45 |显示全部楼层 |坛友微信交流群
  1. // src/main/scala/progscala2/patternmatching/match-types2.sc

  2. def doSeqMatch[T](seq: Seq[T]): String = seq match {
  3.   case Nil => "Nothing"
  4.   case head +: _ => head match {
  5.     case _ : Double => "Double"
  6.     case _ : String => "String"
  7.     case _ => "Unmatched seq element"
  8.   }
  9. }

  10. for {
  11.   x <- Seq(List(5.5,5.6,5.7), List("a", "b"), Nil)
  12. } yield {
  13.   x match {
  14.     case seq: Seq[_] => (s"seq ${doSeqMatch(seq)}", seq)
  15.     case _           => ("unknown!", x)
  16.   }
  17. }
  18. This script returns the desired result, Seq((seq Double,List(5.5, 5.6, 5.7)), (seq String,List(a, b)), (seq Nothing,List())).
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 00:01:03 |显示全部楼层 |坛友微信交流群
  1. Sealed Hierarchies and Exhaustive Matches
  2. Let’s revisit the need for exhaustive matches and consider the situation where we have a sealed class hierarchy, which we discussed in Sealed Class Hierarchies. As an example, suppose we define the following code to represent the allowed message types or “methods” for HTTP:

  3. // src/main/scala/progscala2/patternmatching/http.sc

  4. sealed abstract class HttpMethod() {                                 // 1
  5.     def body: String                                                 // 2
  6.     def bodyLength = body.length
  7. }

  8. case class Connect(body: String) extends HttpMethod                  // 3
  9. case class Delete (body: String) extends HttpMethod
  10. case class Get    (body: String) extends HttpMethod
  11. case class Head   (body: String) extends HttpMethod
  12. case class Options(body: String) extends HttpMethod
  13. case class Post   (body: String) extends HttpMethod
  14. case class Put    (body: String) extends HttpMethod
  15. case class Trace  (body: String) extends HttpMethod

  16. def handle (method: HttpMethod) = method match {                     // 4
  17.   case Connect (body) => s"connect: (length: ${method.bodyLength}) $body"
  18.   case Delete  (body) => s"delete:  (length: ${method.bodyLength}) $body"
  19.   case Get     (body) => s"get:     (length: ${method.bodyLength}) $body"
  20.   case Head    (body) => s"head:    (length: ${method.bodyLength}) $body"
  21.   case Options (body) => s"options: (length: ${method.bodyLength}) $body"
  22.   case Post    (body) => s"post:    (length: ${method.bodyLength}) $body"
  23.   case Put     (body) => s"put:     (length: ${method.bodyLength}) $body"
  24.   case Trace   (body) => s"trace:   (length: ${method.bodyLength}) $body"
  25. }

  26. val methods = Seq(
  27.   Connect("connect body..."),
  28.   Delete ("delete body..."),
  29.   Get    ("get body..."),
  30.   Head   ("head body..."),
  31.   Options("options body..."),
  32.   Post   ("post body..."),
  33.   Put    ("put body..."),
  34.   Trace  ("trace body..."))

  35. methods foreach (method => println(handle(method)))
  36. 1
  37. Define a sealed, abstract base class HttpMethod. Because it is declared sealed, the only allowed subtypes must be defined in this file.

  38. 2
  39. Define a method for the body of the HTTP message.

  40. 3
  41. Define eight case classes that extend HttpMethod. Note that each declares a constructor argument body: String, which is a val because each of these types is a case class. This val implements the abstract def method in HttpMethod.

  42. 4
  43. An exhaustive pattern-match expression, even though we don’t have a default clause, because the method argument can only be an instance of one of the eight case classes we’ve defined.
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 00:05:05 |显示全部楼层 |坛友微信交流群
  1. Using implicitly
  2. Predef defines a method called implicitly. Combined with a type signature addition, it provides a useful shorthand way of defining method signatures that take a single implicit argument, where that argument is a parameterized type.

  3. Consider the following example, which wraps the List method sortBy:

  4. // src/main/scala/progscala2/implicits/implicitly-args.sc
  5. import math.Ordering

  6. case class MyList[A](list: List[A]) {
  7.   def sortBy1[B](f: A => B)(implicit ord: Ordering[B]): List[A] =
  8.     list.sortBy(f)(ord)

  9.   def sortBy2[B : Ordering](f: A => B): List[A] =
  10.     list.sortBy(f)(implicitly[Ordering[B]])
  11. }

  12. val list = MyList(List(1,3,5,2,4))

  13. list sortBy1 (i => -i)
  14. list sortBy2 (i => -i)
  15. List.sortBy is one of several sorting methods available for many of the collections. It takes a function that transforms the arguments into something that satisfies math.Ordering, which is analogous to Java’s Comparable abstraction. An implicit argument is required that knows how to order instances of type B.
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 00:05:49 |显示全部楼层 |坛友微信交流群
  1. Capabilities
  2. Besides passing contexts, implicit arguments can be used to control capabilities.

  3. For example, an implicit user session argument might contain authorization tokens that control whether or not certain API operations can be invoked on behalf of the user or to limit data visibility.

  4. Suppose you are constructing a menu for a user interface and some menu items are shown only if the user is logged in, while others are shown only if the user isn’t logged in:

  5. def createMenu(implicit session: Session): Menu = {
  6.   val defaultItems = List(helpItem, searchItem)
  7.   val accountItems =
  8.     if (session.loggedin()) List(viewAccountItem, editAccountItem)
  9.     else List(loginItem)
  10.   Menu(defaultItems ++ accountItems)
  11. }
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 00:07:16 |显示全部楼层 |坛友微信交流群
  1. Constraining Allowed Instances
  2. Suppose we have a method with parameterized types and we want to constrain the allowed types that can be used for the type parameters.

  3. If the types we want to permit are all subtypes of a common supertype, we can use object-oriented techniques and avoid implicits. Let’s consider that approach first.

  4. We saw an example in Call by Name, Call by Value, where we implemented a resource manager:

  5. object manage {
  6.   def apply[R <: { def close():Unit }, T](resource: => R)(f: R => T) = {...}
  7.   ...
  8. }
  9. The type parameter R must be a subtype of any type with the close():Unit method. Or, if we can assume that all resources we’ll manage implement a Closable trait (recall that traits replace and extend Java interfaces; see Traits: Interfaces and “Mixins” in Scala):

  10. trait Closable {
  11.   def close(): Unit
  12. }
  13. ...
  14. object manage {
  15.   def apply[R <: Closable, T](resource: => R)(f: R => T) = {...}
  16.   ...
  17. }
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 00:14:20 |显示全部楼层 |坛友微信交流群
  1. // src/main/scala/progscala2/implicits/implicit-erasure.sc
  2. object M {
  3.   implicit object IntMarker                                          // 1
  4.   implicit object StringMarker

  5.   def m(seq: Seq[Int])(implicit i: IntMarker.type): Unit =           // 2
  6.     println(s"Seq[Int]: $seq")

  7.   def m(seq: Seq[String])(implicit s: StringMarker.type): Unit =     // 3
  8.     println(s"Seq[String]: $seq")
  9. }

  10. import M._                                                           // 4
  11. m(List(1,2,3))
  12. m(List("one", "two", "three"))
  13. 1
  14. Define two special-purpose implicit objects that will be used to disambiguate the methods affected by type erasure.

  15. 2
  16. Redefinition of the method that takes Seq[Int]. It now has a second argument list expecting an implicit IntMarker. Note the type, IntMarker.type. This is how to reference the type of a singleton object!

  17. 3
  18. The method for Seq[String].

  19. 4
  20. Import the implicit values and the methods, then use them. The code compiles and prints the correct output.
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 00:16:18 |显示全部楼层 |坛友微信交流群
  1. // src/main/scala/progscala2/implicits/phantom-types-pipeline.scala
  2. package progscala.implicits.payroll
  3. import scala.language.implicitConversions

  4. object Pipeline {
  5.   implicit class toPiped[V](value:V) {
  6.     def |>[R] (f : V => R) = f(value)
  7.   }
  8. }

  9. object CalculatePayroll2 {
  10.   def main(args: Array[String]) = {
  11.     import Pipeline._
  12.     import Payroll._

  13.     val e = Employee("Buck Trends", 100000.0F, 0.25F, 200F, 0.10F, 0.05F)
  14.     val pay = start(e) |>
  15.       minus401k        |>
  16.       minusInsurance   |>
  17.       minusTax         |>
  18.       minusFinalDeductions
  19.     val twoWeekGross = e.annualSalary / 26.0F
  20.     val twoWeekNet   = pay.netPay
  21.     val percent      = (twoWeekNet / twoWeekGross) * 100
  22.     println(s"For ${e.name}, the gross vs. net pay every 2 weeks is:")
  23.     println(
  24.       f"  $$${twoWeekGross}%.2f vs. $$${twoWeekNet}%.2f or ${percent}%.1f%%")
  25.   }
  26. }
复制代码

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加JingGuanBbs
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-3-29 13:00