├── concurrency ├── shapes │ ├── target │ │ ├── streams │ │ │ ├── $global │ │ │ │ ├── ivySbt │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── out │ │ │ │ ├── projectDescriptors │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── out │ │ │ │ ├── dependencyPositions │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ ├── update_cache_2.10 │ │ │ │ │ │ ├── input_dsp │ │ │ │ │ │ └── output_dsp │ │ │ │ │ │ └── update_cache_2.11 │ │ │ │ │ │ ├── input_dsp │ │ │ │ │ │ └── output_dsp │ │ │ │ ├── update │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ ├── update_cache_2.10 │ │ │ │ │ │ ├── inputs │ │ │ │ │ │ └── output │ │ │ │ │ │ └── update_cache_2.11 │ │ │ │ │ │ ├── inputs │ │ │ │ │ │ └── output │ │ │ │ ├── ivyConfiguration │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── out │ │ │ │ ├── updateSbtClassifiers │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── out │ │ │ │ └── $global │ │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── out │ │ │ ├── compile │ │ │ │ ├── compile │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── out │ │ │ │ ├── mainClass │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── out │ │ │ │ ├── unmanagedJars │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── export │ │ │ │ ├── unmanagedClasspath │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── export │ │ │ │ ├── internalDependencyClasspath │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── export │ │ │ │ ├── $global │ │ │ │ │ └── $global │ │ │ │ │ │ └── discoveredMainClasses │ │ │ │ │ │ └── data │ │ │ │ ├── exportedProducts │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── export │ │ │ │ ├── copyResources │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ ├── out │ │ │ │ │ │ └── copy-resources │ │ │ │ ├── dependencyClasspath │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── export │ │ │ │ ├── managedClasspath │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── export │ │ │ │ ├── externalDependencyClasspath │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ └── export │ │ │ │ ├── compileIncremental │ │ │ │ │ └── $global │ │ │ │ │ │ └── streams │ │ │ │ │ │ ├── export │ │ │ │ │ │ └── out │ │ │ │ └── run │ │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── out │ │ │ └── runtime │ │ │ │ ├── unmanagedJars │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── export │ │ │ │ ├── unmanagedClasspath │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── export │ │ │ │ ├── exportedProducts │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── export │ │ │ │ ├── internalDependencyClasspath │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── export │ │ │ │ ├── managedClasspath │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── export │ │ │ │ ├── externalDependencyClasspath │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── export │ │ │ │ ├── fullClasspath │ │ │ │ └── $global │ │ │ │ │ └── streams │ │ │ │ │ └── export │ │ │ │ └── dependencyClasspath │ │ │ │ └── $global │ │ │ │ └── streams │ │ │ │ └── export │ │ ├── scala-2.11 │ │ │ └── classes │ │ │ │ └── scalafaq │ │ │ │ └── concurrency │ │ │ │ └── shapes │ │ │ │ ├── Circle.class │ │ │ │ ├── Point$.class │ │ │ │ ├── Point.class │ │ │ │ ├── Shape.class │ │ │ │ ├── Start$.class │ │ │ │ ├── Start.class │ │ │ │ ├── Circle$.class │ │ │ │ ├── Messages.class │ │ │ │ ├── Triangle.class │ │ │ │ ├── Messages$.class │ │ │ │ ├── Rectangle$.class │ │ │ │ ├── Rectangle.class │ │ │ │ ├── Triangle$.class │ │ │ │ ├── Messages$Exit$.class │ │ │ │ ├── Messages$Finished$.class │ │ │ │ ├── Messages$Response$.class │ │ │ │ ├── Messages$Response.class │ │ │ │ ├── ShapesDrawingActor.class │ │ │ │ ├── ShapesDrawingDriver$.class │ │ │ │ ├── ShapesDrawingDriver.class │ │ │ │ ├── ShapesDrawingDriver$$anonfun$1.class │ │ │ │ ├── ShapesDrawingDriver$$anonfun$2.class │ │ │ │ ├── ShapesDrawingActor$$anonfun$receive$1.class │ │ │ │ ├── ShapesDrawingDriver$$anonfun$receive$1.class │ │ │ │ └── ShapesDrawingActor$$anonfun$receive$1$$anonfun$applyOrElse$1.class │ │ ├── resolution-cache │ │ │ ├── org.scala-sbt.temp │ │ │ │ └── temp-module-750703454be73072ce64f1c215ff85550284ae5b │ │ │ │ │ └── 0.13.11 │ │ │ │ │ ├── resolved.xml.properties │ │ │ │ │ └── resolved.xml.xml │ │ │ ├── default │ │ │ │ ├── shapes_2.10 │ │ │ │ │ └── 0.1-SNAPSHOT │ │ │ │ │ │ ├── resolved.xml.properties │ │ │ │ │ │ └── resolved.xml.xml │ │ │ │ └── shapes_2.11 │ │ │ │ │ └── 0.1-SNAPSHOT │ │ │ │ │ ├── resolved.xml.properties │ │ │ │ │ └── resolved.xml.xml │ │ │ └── reports │ │ │ │ ├── default-shapes_2.10-pom.xml │ │ │ │ ├── default-shapes_2.11-pom.xml │ │ │ │ ├── default-shapes_2.10-docs.xml │ │ │ │ ├── default-shapes_2.11-docs.xml │ │ │ │ ├── default-shapes_2.10-optional.xml │ │ │ │ ├── default-shapes_2.10-plugin.xml │ │ │ │ ├── default-shapes_2.10-provided.xml │ │ │ │ ├── default-shapes_2.10-sources.xml │ │ │ │ ├── default-shapes_2.11-optional.xml │ │ │ │ ├── default-shapes_2.11-plugin.xml │ │ │ │ ├── default-shapes_2.11-provided.xml │ │ │ │ ├── default-shapes_2.11-sources.xml │ │ │ │ ├── default-shapes_2.10-compile.xml │ │ │ │ ├── default-shapes_2.10-runtime.xml │ │ │ │ ├── default-shapes_2.10-test.xml │ │ │ │ ├── default-shapes_2.10-compile-internal.xml │ │ │ │ ├── default-shapes_2.10-runtime-internal.xml │ │ │ │ ├── default-shapes_2.10-test-internal.xml │ │ │ │ ├── org.scala-sbt.temp-temp-module-750703454be73072ce64f1c215ff85550284ae5b-component.xml │ │ │ │ ├── default-shapes_2.11-runtime.xml │ │ │ │ ├── default-shapes_2.11-test.xml │ │ │ │ ├── default-shapes_2.11-runtime-internal.xml │ │ │ │ ├── default-shapes_2.11-compile-internal.xml │ │ │ │ ├── default-shapes_2.11-test-internal.xml │ │ │ │ ├── default-shapes_2.11-compile.xml │ │ │ │ ├── ivy-report.css │ │ │ │ ├── default-shapes_2.10-scala-tool.xml │ │ │ │ └── default-shapes_2.11-scala-tool.xml │ │ └── .history │ ├── project │ │ └── target │ │ │ └── config-classes │ │ │ ├── $966700fb627893f13fdc.cache │ │ │ ├── $c500e40e914d0c7adfbd.cache │ │ │ ├── $ff09c84cae7e9773912c.cache │ │ │ ├── $966700fb627893f13fdc$.class │ │ │ ├── $966700fb627893f13fdc.class │ │ │ ├── $c500e40e914d0c7adfbd$.class │ │ │ ├── $c500e40e914d0c7adfbd.class │ │ │ ├── $ff09c84cae7e9773912c$.class │ │ │ ├── $ff09c84cae7e9773912c.class │ │ │ ├── $966700fb627893f13fdc$$anonfun$$sbtdef$1.class │ │ │ ├── $c500e40e914d0c7adfbd$$anonfun$$sbtdef$1.class │ │ │ └── $ff09c84cae7e9773912c$$anonfun$$sbtdef$1.class │ ├── build.sbt │ ├── Shapes.scala │ ├── ShapesDrawingActor.scala │ └── ShapesDrawingDriver.scala ├── images │ └── shapes_result.jpg └── Rendering_Example.ipynb ├── collections ├── test.txt ├── images │ ├── list.jpg │ ├── stream1.jpg │ ├── stream2.jpg │ ├── stream3.jpg │ ├── vector1.jpg │ ├── vector2.jpg │ ├── vector3.jpg │ └── collections_hierarchy.jpg └── work_with_lists.ipynb ├── basics ├── fileBulkReaderTestFile.txt └── basics1.ipynb ├── pattern_match └── images │ └── switch_anno.jpg ├── .gitignore ├── functional ├── for_in_depth.ipynb ├── universal_operations.ipynb ├── combinators.ipynb └── functional_data_structure.ipynb ├── type_system ├── structural_type.ipynb ├── path-dependent_type.ipynb └── type_bound.ipynb ├── LICENSE ├── README.md └── implicits ├── buildin_implicits.ipynb ├── implicit_conversion.ipynb └── implicit_parameter.ipynb /concurrency/shapes/target/streams/$global/ivySbt/$global/streams/out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/compile/$global/streams/out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/mainClass/$global/streams/out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /collections/test.txt: -------------------------------------------------------------------------------- 1 | Line 1 2 | Line 2 3 | Line 3 4 | Line 4 5 | Line 5 6 | Line 6 -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/projectDescriptors/$global/streams/out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/unmanagedJars/$global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/runtime/unmanagedJars/$global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/unmanagedClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/runtime/unmanagedClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$966700fb627893f13fdc.cache: -------------------------------------------------------------------------------- 1 | sbt.internals.DslEntry -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$c500e40e914d0c7adfbd.cache: -------------------------------------------------------------------------------- 1 | sbt.internals.DslEntry -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$ff09c84cae7e9773912c.cache: -------------------------------------------------------------------------------- 1 | sbt.internals.DslEntry -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/internalDependencyClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /collections/images/list.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/collections/images/list.jpg -------------------------------------------------------------------------------- /collections/images/stream1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/collections/images/stream1.jpg -------------------------------------------------------------------------------- /collections/images/stream2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/collections/images/stream2.jpg -------------------------------------------------------------------------------- /collections/images/stream3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/collections/images/stream3.jpg -------------------------------------------------------------------------------- /collections/images/vector1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/collections/images/vector1.jpg -------------------------------------------------------------------------------- /collections/images/vector2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/collections/images/vector2.jpg -------------------------------------------------------------------------------- /collections/images/vector3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/collections/images/vector3.jpg -------------------------------------------------------------------------------- /basics/fileBulkReaderTestFile.txt: -------------------------------------------------------------------------------- 1 | this is a file for read method of FileBulkReader class 2 | do some work 3 | def countLines -------------------------------------------------------------------------------- /concurrency/images/shapes_result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/images/shapes_result.jpg -------------------------------------------------------------------------------- /pattern_match/images/switch_anno.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/pattern_match/images/switch_anno.jpg -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/$global/$global/discoveredMainClasses/data: -------------------------------------------------------------------------------- 1 | /scalafaq.concurrency.shapes.ShapesDrawingDriver -------------------------------------------------------------------------------- /collections/images/collections_hierarchy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/collections/images/collections_hierarchy.jpg -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/exportedProducts/$global/streams/export: -------------------------------------------------------------------------------- 1 | E:\IdeaProjects\ScalaFAQ\concurrency\shapes\target\scala-2.11\classes 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/runtime/exportedProducts/$global/streams/export: -------------------------------------------------------------------------------- 1 | E:\IdeaProjects\ScalaFAQ\concurrency\shapes\target\scala-2.11\classes 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/dependencyPositions/$global/streams/update_cache_2.10/input_dsp: -------------------------------------------------------------------------------- 1 | org.scala-lang scala-library2.10.6 -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/copyResources/$global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] Copy resource mappings:  2 | [debug]   3 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/runtime/internalDependencyClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | E:\IdeaProjects\ScalaFAQ\concurrency\shapes\target\scala-2.11\classes 2 | -------------------------------------------------------------------------------- /concurrency/shapes/build.sbt: -------------------------------------------------------------------------------- 1 | name := "shapes" 2 | 3 | scalaVersion := "2.11.8" 4 | 5 | libraryDependencies += 6 | "com.typesafe.akka" % "akka-actor_2.11" % "2.4.1" 7 | -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$966700fb627893f13fdc$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$966700fb627893f13fdc$.class -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$966700fb627893f13fdc.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$966700fb627893f13fdc.class -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$c500e40e914d0c7adfbd$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$c500e40e914d0c7adfbd$.class -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$c500e40e914d0c7adfbd.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$c500e40e914d0c7adfbd.class -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$ff09c84cae7e9773912c$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$ff09c84cae7e9773912c$.class -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$ff09c84cae7e9773912c.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$ff09c84cae7e9773912c.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Circle.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Circle.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Point$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Point$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Point.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Point.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Shape.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Shape.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Start$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Start$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Start.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Start.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Circle$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Circle$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Triangle.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Triangle.class -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/dependencyPositions/$global/streams/update_cache_2.11/input_dsp: -------------------------------------------------------------------------------- 1 | org.scala-lang scala-library2.11.8com.typesafe.akkaakka-actor_2.112.4.1 -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/copyResources/$global/streams/copy-resources: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/streams/compile/copyResources/$global/streams/copy-resources -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Rectangle$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Rectangle$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Rectangle.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Rectangle.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Triangle$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Triangle$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/update/$global/streams/update_cache_2.10/inputs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/streams/$global/update/$global/streams/update_cache_2.10/inputs -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/update/$global/streams/update_cache_2.10/output: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/streams/$global/update/$global/streams/update_cache_2.10/output -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/update/$global/streams/update_cache_2.11/inputs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/streams/$global/update/$global/streams/update_cache_2.11/inputs -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/update/$global/streams/update_cache_2.11/output: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/streams/$global/update/$global/streams/update_cache_2.11/output -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$966700fb627893f13fdc$$anonfun$$sbtdef$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$966700fb627893f13fdc$$anonfun$$sbtdef$1.class -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$c500e40e914d0c7adfbd$$anonfun$$sbtdef$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$c500e40e914d0c7adfbd$$anonfun$$sbtdef$1.class -------------------------------------------------------------------------------- /concurrency/shapes/project/target/config-classes/$ff09c84cae7e9773912c$$anonfun$$sbtdef$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/project/target/config-classes/$ff09c84cae7e9773912c$$anonfun$$sbtdef$1.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$Exit$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$Exit$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$Finished$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$Finished$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$Response$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$Response$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$Response.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/Messages$Response.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingActor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingActor.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver$.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver$.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver.class -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/ivyConfiguration/$global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] Other repositories: 2 | [debug] Default repositories: 3 | [debug] Using inline dependencies specified in Scala. 4 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/updateSbtClassifiers/$global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] Other repositories: 2 | [debug] Default repositories: 3 | [debug] Using inline dependencies specified in Scala. 4 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/dependencyPositions/$global/streams/update_cache_2.10/output_dsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/streams/$global/dependencyPositions/$global/streams/update_cache_2.10/output_dsp -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/dependencyPositions/$global/streams/update_cache_2.11/output_dsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/streams/$global/dependencyPositions/$global/streams/update_cache_2.11/output_dsp -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver$$anonfun$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver$$anonfun$1.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver$$anonfun$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver$$anonfun$2.class -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | 4 | # sbt specific 5 | .cache 6 | .history 7 | .lib/ 8 | dist/* 9 | target/ 10 | lib_managed/ 11 | src_managed/ 12 | project/boot/ 13 | project/plugins/project/ 14 | 15 | # Scala-IDE specific 16 | .scala_dependencies 17 | .worksheet 18 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/$global/$global/$global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] Other repositories: 2 | [debug] Default repositories: 3 | [debug] Other repositories: 4 | [debug] Default repositories: 5 | -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingActor$$anonfun$receive$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingActor$$anonfun$receive$1.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver$$anonfun$receive$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingDriver$$anonfun$receive$1.class -------------------------------------------------------------------------------- /concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingActor$$anonfun$receive$1$$anonfun$applyOrElse$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonding1354/ScalaFAQ/HEAD/concurrency/shapes/target/scala-2.11/classes/scalafaq/concurrency/shapes/ShapesDrawingActor$$anonfun$receive$1$$anonfun$applyOrElse$1.class -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/dependencyClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar;C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar;C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/managedClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar;C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar;C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/runtime/managedClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar;C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar;C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/externalDependencyClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar;C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar;C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/runtime/externalDependencyClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar;C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar;C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/runtime/fullClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | E:\IdeaProjects\ScalaFAQ\concurrency\shapes\target\scala-2.11\classes;C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar;C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar;C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/runtime/dependencyClasspath/$global/streams/export: -------------------------------------------------------------------------------- 1 | E:\IdeaProjects\ScalaFAQ\concurrency\shapes\target\scala-2.11\classes;C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar;C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar;C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/org.scala-sbt.temp/temp-module-750703454be73072ce64f1c215ff85550284ae5b/0.13.11/resolved.xml.properties: -------------------------------------------------------------------------------- 1 | #org.scala-sbt.temp#temp-module-750703454be73072ce64f1c215ff85550284ae5b;0.13.11 resolved revisions 2 | #Sat Apr 23 19:31:10 CST 2016 3 | +organisation\:\#@\#\:+org.scala-sbt\:\#@\#\:+branch\:\#@\#\:+@\#\:NULL\:\#@\:\#@\#\:+module\:\#@\#\:+compiler-interface\:\#@\#\:+revision\:\#@\#\:+0.13.11\:\#@\#\:=0.13.11 release 0.13.11 null 4 | -------------------------------------------------------------------------------- /concurrency/shapes/target/.history: -------------------------------------------------------------------------------- 1 | run 2 | compile 3 | libraryDependencies += "com.typesafe.akka" % "akka-actor_2.11" % "2.4.1" 4 | libraryDependencies += "com.typesafe.akka" %% "akka-actor_2.11" % "2.4.1" 5 | libraryDependencies += 6 | name := "shapes" 7 | name :: "shapes" 8 | name ::= "shapes" 9 | exit 10 | compile 11 | exit 12 | compile 13 | :q 14 | exit 15 | libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.4.1" 16 | xit 17 | exit 18 | idea 19 | help 20 | plugins 21 | compile 22 | run 23 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/default/shapes_2.10/0.1-SNAPSHOT/resolved.xml.properties: -------------------------------------------------------------------------------- 1 | #default#shapes_2.10;0.1-SNAPSHOT resolved revisions 2 | #Sat Apr 23 18:46:30 CST 2016 3 | +organisation\:\#@\#\:+org.scala-lang\:\#@\#\:+branch\:\#@\#\:+@\#\:NULL\:\#@\:\#@\#\:+module\:\#@\#\:+scala-library\:\#@\#\:+revision\:\#@\#\:+2.10.6\:\#@\#\:=2.10.6 ? 2.10.6 null 4 | +organisation\:\#@\#\:+org.scala-lang\:\#@\#\:+branch\:\#@\#\:+@\#\:NULL\:\#@\:\#@\#\:+module\:\#@\#\:+scala-compiler\:\#@\#\:+revision\:\#@\#\:+2.10.6\:\#@\#\:=2.10.6 release 2.10.6 null 5 | -------------------------------------------------------------------------------- /concurrency/shapes/Shapes.scala: -------------------------------------------------------------------------------- 1 | package scalafaq.concurrency.shapes 2 | 3 | case class Point(x: Double = 0.0, y: Double = 0.0) 4 | 5 | abstract class Shape() { 6 | // draw方法接受一个函数参数 7 | // 每个图形对象都会将自己的字符格式传给函数f,由f完成绘制工作 8 | def draw(f: String => Unit): Unit = f(s"draw: ${this.toString}") 9 | } 10 | 11 | case class Circle(center: Point, radius: Double) extends Shape 12 | case class Rectangle(lowerLeft: Point, height: Double, width: Double) extends Shape 13 | case class Triangle(point1: Point, point2: Point, point3: Point) extends Shape 14 | 15 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-docs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-docs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-optional.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-provided.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-sources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-optional.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-provided.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-sources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /functional/for_in_depth.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [] 11 | } 12 | ], 13 | "metadata": { 14 | "kernelspec": { 15 | "display_name": "Scala 2.11", 16 | "language": "scala211", 17 | "name": "scala211" 18 | }, 19 | "language_info": { 20 | "codemirror_mode": "text/x-scala", 21 | "file_extension": ".scala", 22 | "mimetype": "text/x-scala", 23 | "name": "scala211", 24 | "pygments_lexer": "scala", 25 | "version": "2.11.6" 26 | } 27 | }, 28 | "nbformat": 4, 29 | "nbformat_minor": 0 30 | } 31 | -------------------------------------------------------------------------------- /type_system/structural_type.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [] 11 | } 12 | ], 13 | "metadata": { 14 | "kernelspec": { 15 | "display_name": "Scala 2.11", 16 | "language": "scala211", 17 | "name": "scala211" 18 | }, 19 | "language_info": { 20 | "codemirror_mode": "text/x-scala", 21 | "file_extension": ".scala", 22 | "mimetype": "text/x-scala", 23 | "name": "scala211", 24 | "pygments_lexer": "scala", 25 | "version": "2.11.6" 26 | } 27 | }, 28 | "nbformat": 4, 29 | "nbformat_minor": 0 30 | } 31 | -------------------------------------------------------------------------------- /type_system/path-dependent_type.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [] 11 | } 12 | ], 13 | "metadata": { 14 | "kernelspec": { 15 | "display_name": "Scala 2.11", 16 | "language": "scala211", 17 | "name": "scala211" 18 | }, 19 | "language_info": { 20 | "codemirror_mode": "text/x-scala", 21 | "file_extension": ".scala", 22 | "mimetype": "text/x-scala", 23 | "name": "scala211", 24 | "pygments_lexer": "scala", 25 | "version": "2.11.6" 26 | } 27 | }, 28 | "nbformat": 4, 29 | "nbformat_minor": 0 30 | } 31 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/default/shapes_2.11/0.1-SNAPSHOT/resolved.xml.properties: -------------------------------------------------------------------------------- 1 | #default#shapes_2.11;0.1-SNAPSHOT resolved revisions 2 | #Sat Apr 23 19:30:10 CST 2016 3 | +organisation\:\#@\#\:+org.scala-lang\:\#@\#\:+branch\:\#@\#\:+@\#\:NULL\:\#@\:\#@\#\:+module\:\#@\#\:+scala-library\:\#@\#\:+revision\:\#@\#\:+2.11.8\:\#@\#\:=2.11.8 ? 2.11.8 null 4 | +organisation\:\#@\#\:+com.typesafe.akka\:\#@\#\:+branch\:\#@\#\:+@\#\:NULL\:\#@\:\#@\#\:+module\:\#@\#\:+akka-actor_2.11\:\#@\#\:+revision\:\#@\#\:+2.4.1\:\#@\#\:=2.4.1 release 2.4.1 null 5 | +organisation\:\#@\#\:+org.scala-lang\:\#@\#\:+branch\:\#@\#\:+@\#\:NULL\:\#@\:\#@\#\:+module\:\#@\#\:+scala-compiler\:\#@\#\:+revision\:\#@\#\:+2.11.8\:\#@\#\:=2.11.8 release 2.11.8 null 6 | -------------------------------------------------------------------------------- /concurrency/shapes/ShapesDrawingActor.scala: -------------------------------------------------------------------------------- 1 | package scalafaq.concurrency.shapes 2 | import akka.actor.Actor 3 | 4 | object Messages { 5 | object Exit 6 | object Finished 7 | case class Response(message: String) 8 | } 9 | 10 | 11 | class ShapesDrawingActor extends Actor { 12 | import Messages._ 13 | 14 | def receive = { 15 | case s: Shape => 16 | s.draw(str => println(s"ShapesDrawingActor: $str")) 17 | sender ! Response(s"ShapesDrawingActor: $s drawn") 18 | case Exit => 19 | println(s"ShapesDrawingActor: exiting...") 20 | sender ! Finished 21 | case unexpected => //default. Equivalent to "unexpected: Any" 22 | val response = Response(s"Error: Unknown message: $unexpected") 23 | println(s"ShapesDrawingActor: $response") 24 | sender ! response 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/org.scala-sbt.temp/temp-module-750703454be73072ce64f1c215ff85550284ae5b/0.13.11/resolved.xml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/compileIncremental/$global/streams/export: -------------------------------------------------------------------------------- 1 | scalac -bootclasspath D:\Java\jdk1.8.0_20\jre\lib\resources.jar;D:\Java\jdk1.8.0_20\jre\lib\rt.jar;D:\Java\jdk1.8.0_20\jre\lib\sunrsasign.jar;D:\Java\jdk1.8.0_20\jre\lib\jsse.jar;D:\Java\jdk1.8.0_20\jre\lib\jce.jar;D:\Java\jdk1.8.0_20\jre\lib\charsets.jar;D:\Java\jdk1.8.0_20\jre\lib\jfr.jar;D:\Java\jdk1.8.0_20\jre\classes;C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar -classpath E:\IdeaProjects\ScalaFAQ\concurrency\shapes\target\scala-2.11\classes;C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar;C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar E:\IdeaProjects\ScalaFAQ\concurrency\shapes\Shapes.scala E:\IdeaProjects\ScalaFAQ\concurrency\shapes\ShapesDrawingActor.scala E:\IdeaProjects\ScalaFAQ\concurrency\shapes\ShapesDrawingDriver.scala 2 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/compileIncremental/$global/streams/out: -------------------------------------------------------------------------------- 1 | [debug] [naha]  2 | [debug] [naha] Initial source changes:  3 | [debug] [naha] removed:Set() 4 | [debug] [naha] added: Set() 5 | [debug] [naha] modified: Set() 6 | [debug] [naha] Invalidated products: Set() 7 | [debug] [naha] External API changes: API Changes: Set() 8 | [debug] [naha] Modified binary dependencies: Set() 9 | [debug] [naha] Initial directly invalidated sources: Set() 10 | [debug] [naha]  11 | [debug] [naha] Sources indirectly invalidated by: 12 | [debug] [naha] product: Set() 13 | [debug] [naha] binary dep: Set() 14 | [debug] [naha] external source: Set() 15 | [debug] All initially invalidated sources: Set() 16 | -------------------------------------------------------------------------------- /functional/universal_operations.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 遍历、映射、过滤、折叠、归约和向左向右遍历\n", 8 | "常见的集合类型——序列、列表、集合、数组、树以及其他类似的类型,都支持基于只读遍历的通用操作。这一标准性可以被充分利用起来,特别是你是想的某个“容器”类型也支持这些操作的情况。" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## 1 遍历" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": { 22 | "collapsed": true 23 | }, 24 | "outputs": [], 25 | "source": [] 26 | } 27 | ], 28 | "metadata": { 29 | "kernelspec": { 30 | "display_name": "Scala 2.11", 31 | "language": "scala211", 32 | "name": "scala211" 33 | }, 34 | "language_info": { 35 | "codemirror_mode": "text/x-scala", 36 | "file_extension": ".scala", 37 | "mimetype": "text/x-scala", 38 | "name": "scala211", 39 | "pygments_lexer": "scala", 40 | "version": "2.11.6" 41 | } 42 | }, 43 | "nbformat": 4, 44 | "nbformat_minor": 0 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jason Ding 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /concurrency/shapes/target/streams/compile/run/$global/streams/out: -------------------------------------------------------------------------------- 1 | [info] Running scalafaq.concurrency.shapes.ShapesDrawingDriver  2 | [debug] Waiting for threads to exit or System.exit to be called. 3 | [debug]  Classpath: 4 | [debug]  E:\IdeaProjects\ScalaFAQ\concurrency\shapes\target\scala-2.11\classes 5 | [debug]  C:\Users\Think\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.8.jar 6 | [debug]  C:\Users\Think\.ivy2\cache\com.typesafe.akka\akka-actor_2.11\jars\akka-actor_2.11-2.4.1.jar 7 | [debug]  C:\Users\Think\.ivy2\cache\com.typesafe\config\bundles\config-1.3.0.jar 8 | [debug] Waiting for thread run-main-0 to terminate. 9 | [debug]  Thread run-main-0 exited. 10 | [debug] Waiting for thread DrawinActorSystem-akka.actor.default-dispatcher-2 to terminate. 11 | [debug]  Thread DrawinActorSystem-akka.actor.default-dispatcher-2 exited. 12 | [debug] Interrupting remaining threads (should be all daemons). 13 | [debug] Sandboxed run complete.. 14 | [debug] Exited with code 0 15 | -------------------------------------------------------------------------------- /concurrency/shapes/ShapesDrawingDriver.scala: -------------------------------------------------------------------------------- 1 | package scalafaq.concurrency.shapes 2 | import akka.actor.{Props, ActorRef, ActorSystem, Actor} 3 | 4 | private object Start 5 | 6 | class ShapesDrawingDriver(drawerActor: ActorRef) extends Actor { 7 | import Messages._ 8 | 9 | def receive = { 10 | case Start => 11 | drawerActor ! Circle(Point(0.0, 0.0), 1.0) 12 | drawerActor ! Rectangle(Point(0.0, 0.0), 2, 5) 13 | drawerActor ! 3.14159 14 | drawerActor ! Triangle(Point(0.0, 0.0), Point(2.0, 0.0), Point(1.0, 2.0)) 15 | drawerActor ! Exit 16 | case Finished => 17 | println(s"ShapesDrawingDriver: cleaning up...") 18 | context.system.shutdown() 19 | case response: Response => 20 | println("ShapesDrawingDriver: Response =" + response) 21 | case unexpected => 22 | println("ShapesDrawingDriver: ERROR: Receive an unexpected message =" + unexpected) 23 | } 24 | } 25 | 26 | object ShapesDrawingDriver { 27 | def main(args: Array[String]) { 28 | val system = ActorSystem("DrawinActorSystem") 29 | val drawer = system.actorOf(Props(new ShapesDrawingActor), "drawingActor") 30 | val driver = system.actorOf(Props(new ShapesDrawingDriver(drawer)), "drawingDriver") 31 | driver ! Start 32 | system.shutdown 33 | } 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-compile.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-runtime.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-compile-internal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-runtime-internal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-test-internal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/default/shapes_2.10/0.1-SNAPSHOT/resolved.xml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | shapes 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/default/shapes_2.11/0.1-SNAPSHOT/resolved.xml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | shapes 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScalaFAQ 2 | --- 3 | 本项目是根据《Programming Scala》、《Scala Cookbook》、《Scala for the Impatient》等书的学习示例进行的提炼总结,还包含了很多Scala的基本知识点和技术细节。希望通过该项目的总结能够及时总结Scala编程遇到的常见问题和解决方法,对Scala语法和应用有更加深入的理解。 4 | 5 | 感谢jupyter-scala项目让我可以在jupyter notebook上编写Scala程序,并进行交互式的总结。 6 | 7 | --- 8 | ## 基本概念 9 | - [基本知识点1](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/basics/basics1.ipynb) 10 | 11 | 介绍了偏函数、Future、递归技巧、类型推断、Option类型、参数化类型等几个概念和基本方法 12 | - [基本知识点2](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/basics/basics2.ipynb) 13 | 14 | 介绍了无参数方法、for推导式、异常处理、惰性求值、枚举、trait等几个概念和方法 15 | []() 16 | 17 | ## 模式匹配 18 | - [简单匹配](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/pattern_match/simple_matching.ipynb) 19 | - []() 20 | 21 | ## 隐式转换 22 | - [隐式参数](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/implicits/implicit_parameter.ipynb) 23 | 24 | 介绍了有关隐式参数的基本方法和规则 25 | - [隐式转换](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/implicits/implicit_conversion.ipynb) 26 | 27 | 介绍了隐式转换的基本概念,介绍了Map中的->表达式的隐式转换原理,通过隐式转换为scala.StringContext方法添加新的字符串插入器 28 | 29 | 30 | ## 函数式编程 31 | - [函数式编程初步](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/functional/functional_intro.ipynb) 32 | 33 | 介绍了函数式编程的一些基本概念,包括匿名函数、闭包、尾递归、偏函数、偏应用函数、柯里化等 34 | - [函数式数据结构](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/functional/functional_data_structure.ipynb) 35 | 36 | 介绍了函数式数据结构的基本特点和主要类型 37 | - [函数式集合类型的通用操作](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/functional/universal_operations.ipynb) 38 | 39 | 介绍了遍历、映射、过滤、折叠、归约和向左向右遍历等操作的基本原理 40 | - [软件复用与组合器](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/functional/combinators.ipynb) 41 | 42 | 函数式编程语言通过组合器来实现软件复用组件,将数据和需要实现的行为分离,从而能够实现更加复杂的结构 43 | 44 | ## 面向对象 45 | - []() 46 | 47 | ## 类型系统 48 | - [参数化类型与型变标记](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/type_system/parametered_type.ipynb) 49 | 50 | 介绍了Scala类型系统中的参数化类型以及型变(variance)标记 51 | - [类型边界 ](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/type_system/type_bound.ipynb) 52 | 53 | 介绍类型边界以及使用类型边界解决型变故障的问题 54 | - [虚类型](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/type_system/phantom_type.ipynb) 55 | 56 | 介绍了使用虚类型来定义按照一定顺序流程的工作流设计问题的解决方法 57 | - []() 58 | 59 | 60 | ## 并发与Actor 61 | - [actor信息交互过程](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/concurrency/Rendering_Example.ipynb) 62 | 63 | 该示例模拟了场景渲染过程中驱动actor和绘图actor的信息交互过程 64 | 65 | 66 | ## Scala集合库 67 | - [Scala集合库概况](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/collections/collection_intro.ipynb) 68 | 69 | 介绍了Scala集合库的主要集合类,介绍了Vector、List、Stream、ArrayBuffer的基本原理 70 | - [Scala集合库继承层次](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/collections/collection_hierarchy.ipynb) 71 | 72 | 介绍了集合库继承层次中Traversable、Iterable、Seq等特质的基本原理 73 | - [使用List数据结构解决一系列小问题](http://nbviewer.jupyter.org/github/jasonding1354/ScalaFAQ/blob/master/collections/work_with_lists.ipynb) 74 | 75 | 介绍了List的编程实例 76 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/org.scala-sbt.temp-temp-module-750703454be73072ce64f1c215ff85550284ae5b-component.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /implicits/buildin_implicits.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 1 Scala内置的各种隐式\n", 8 | "Scala 2.11版库源代码中定义了超过300个隐式方法、隐式值和隐式类型。它们当中大多数都是隐式方法,而隐式方法中的多数则被用于将某一类型转换成另一类型。" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "### 1.1 AnyVal类型的隐式转换\n", 16 | "AnyVal类型的所有伴生对象均提供了丰富的隐式转换方法,例如将Int值转换为Long值,可以使用int2long方法。\n", 17 | "\n", 18 | "取自Byte的伴生对象:\n", 19 | "``` scala\n", 20 | "implicit def byte2short(x: Byte): Short = x.toShort\n", 21 | "implicit def byte2int(x: Byte): Int = x.toInt\n", 22 | "implicit def byte2long(x: Byte): Long = x.toLong\n", 23 | "implicit def byte2float(x: Byte): Float = x.toFloat\n", 24 | "implicit def byte2double(x: Byte): Double = x.toDouble\n", 25 | "```\n", 26 | "取自Char的伴生对象:\n", 27 | "``` scala\n", 28 | "// From the scala.Char companion object:\n", 29 | "implicit def char2int(x: Char): Int = x.toInt\n", 30 | "implicit def char2long(x: Char): Long = x.toLong\n", 31 | "implicit def char2float(x: Char): Float = x.toFloat\n", 32 | "implicit def char2double(x: Char): Double = x.toDouble\n", 33 | "```\n", 34 | "取自Short的伴生对象:\n", 35 | "``` scala\n", 36 | "implicit def short2int(x: Short): Int = x.toInt\n", 37 | "implicit def short2long(x: Short): Long = x.toLong\n", 38 | "implicit def short2float(x: Short): Float = x.toFloat\n", 39 | "implicit def short2double(x: Short): Double = x.toDouble\n", 40 | "```\n", 41 | "取自Int的伴生对象:\n", 42 | "``` scala\n", 43 | "implicit def int2long(x: Int): Long = x.toLong\n", 44 | "implicit def int2float(x: Int): Float = x.toFloat\n", 45 | "implicit def int2double(x: Int): Double = x.toDouble\n", 46 | "```\n", 47 | "取自Long的伴生对象:\n", 48 | "``` scala\n", 49 | "implicit def long2float(x: Long): Float = x.toFloat\n", 50 | "implicit def long2double(x: Long): Double = x.toDouble\n", 51 | "```\n", 52 | "取自Float的伴生对象:\n", 53 | "``` scala\n", 54 | "implicit def float2double(x: Float): Double = x.toDouble\n", 55 | "```\n", 56 | "\n", 57 | "BigInt和BigDecimal类定义在scala.math包中,他们可以转换来自AnyVal类型和Java中对应的实现类型。\n", 58 | "取自BigDecimal的伴生对象:\n", 59 | "``` scala\n", 60 | "implicit def int2bigDecimal(i: Int): BigDecimal = apply(i)\n", 61 | "implicit def long2bigDecimal(l: Long): BigDecimal = apply(l)\n", 62 | "implicit def double2bigDecimal(d: Double): BigDecimal = ...\n", 63 | "implicit def javaBigDecimal2bigDecimal(x: BigDec): BigDecimal = apply(x)\n", 64 | "```\n", 65 | "其中调用apply方法时,调用了BigDecimal伴生对象的apply工厂方法。\n", 66 | "\n", 67 | "取自BigInt的伴生对象:\n", 68 | "``` scala\n", 69 | "implicit def int2bigInt(i: Int): BigInt = apply(i)\n", 70 | "implicit def long2bigInt(l: Long): BigInt = apply(l)\n", 71 | "implicit def javaBigInteger2bigInt(x: BigInteger): BigInt = apply(x)\n", 72 | "```" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "### 1.2 转换自Java中的类型\n", 80 | "Scala使用了一些Java中的类型,像Array[T]和String类型,和它们对应的ArrayOps[T]和StringOps类型向所有Scala集合提供常用的方法。\n", 81 | "\n", 82 | "其他的转换函数则定义在名称中包含Wrapper单词的类型中。" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "### 1.3 @inline注解\n", 90 | "Predef中定义了大多数的隐式定义。其中一些隐式定义包含了@inline标注,这一标注鼓励编译器努力尝试将函数调用内联,以减少栈帧开销。与之对应的是@oninline标注,该标注阻止编译器将方法内联化。" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": { 96 | "collapsed": true 97 | }, 98 | "source": [ 99 | "## 2 CanBuildFrom隐式解读" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": { 106 | "collapsed": true 107 | }, 108 | "outputs": [], 109 | "source": [] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": {}, 114 | "source": [ 115 | "## 3 FileWrapper隐式解读" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": { 122 | "collapsed": true 123 | }, 124 | "outputs": [], 125 | "source": [] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "## 合理使用隐式\n", 132 | "隐式转换机制为构建DSL和简化代码提供了强大的工具。不过由于传递隐式参数和隐式值几乎不可见,这增加了理解代码的难度。\n", 133 | "\n", 134 | "为了提高隐式可见性,推荐的方法是**将隐式值统一放到名为implicits的特殊包或名为Implicits的对象中。这种方式使得读者一旦遇到导入语句中的implicit字样时,便会刘怡到除了Scala内置的隐式之外,还存在一些其他的隐式。**" 135 | ] 136 | } 137 | ], 138 | "metadata": { 139 | "kernelspec": { 140 | "display_name": "Scala 2.11", 141 | "language": "scala211", 142 | "name": "scala211" 143 | }, 144 | "language_info": { 145 | "codemirror_mode": "text/x-scala", 146 | "file_extension": ".scala", 147 | "mimetype": "text/x-scala", 148 | "name": "scala211", 149 | "pygments_lexer": "scala", 150 | "version": "2.11.6" 151 | } 152 | }, 153 | "nbformat": 4, 154 | "nbformat_minor": 0 155 | } 156 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-runtime.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-runtime-internal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-compile-internal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-test-internal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-compile.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/ivy-report.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | body { 20 | font-family:"Trebuchet MS",Verdana,Geneva,Arial,Helvetica,sans-serif; 21 | font-size:small; 22 | } 23 | 24 | div#logo { 25 | float: right; 26 | padding-left: 10px; 27 | padding-bottom: 10px; 28 | background: white; 29 | text-align: center; 30 | } 31 | 32 | #logo img { 33 | border: 0; 34 | } 35 | 36 | div#date { 37 | font-style: italic; 38 | padding-left: 60px; 39 | padding-bottom: 40px; 40 | } 41 | 42 | 43 | h1 { 44 | margin-bottom:2px; 45 | 46 | border-color:#7A9437; 47 | border-style:solid; 48 | border-width:0 0 3px 0; 49 | } 50 | 51 | span#module { 52 | color:#7A9437; 53 | text-decoration:none; 54 | } 55 | 56 | span#organisation { 57 | color:black; 58 | text-decoration:none; 59 | } 60 | 61 | #confmenu { 62 | color: #000; 63 | border-bottom: 2px solid black; 64 | margin: 12px 0px 0px 0px; 65 | padding: 0px; 66 | z-index: 1; 67 | padding-left: 10px 68 | } 69 | 70 | #confmenu li { 71 | display: inline; 72 | overflow: hidden; 73 | list-style-type: none; 74 | } 75 | 76 | #confmenu a, a.active { 77 | color: #DEDECF; 78 | background: #898B5E; 79 | font: bold 1em "Trebuchet MS", Arial, sans-serif; 80 | border: 2px solid black; 81 | padding: 2px 5px 0px 5px; 82 | text-decoration: none; 83 | } 84 | 85 | /* 86 | background: #ABAD85 #CED4BD 87 | background: #DEE4CD 88 | */ 89 | 90 | #confmenu a.active { 91 | color: #7A9437; 92 | background: #DEE4CD; 93 | border-bottom: 3px solid #DEE4CD; 94 | } 95 | 96 | #confmenu a:hover { 97 | color: #fff; 98 | background: #ADC09F; 99 | } 100 | 101 | #confmenu a:visited { 102 | color: #DEDECF; 103 | } 104 | 105 | #confmenu a.active:visited { 106 | color: #7A9437; 107 | } 108 | 109 | #confmenu a.active:hover { 110 | background: #DEE4CD; 111 | color: #DEDECF; 112 | } 113 | 114 | #content { 115 | background: #DEE4CD; 116 | padding: 20px; 117 | border: 2px solid black; 118 | border-top: none; 119 | z-index: 2; 120 | } 121 | 122 | #content a { 123 | text-decoration: none; 124 | color: #E8E9BE; 125 | } 126 | 127 | #content a:hover { 128 | background: #898B5E; 129 | } 130 | 131 | 132 | h2 { 133 | margin-bottom:2px; 134 | font-size:medium; 135 | 136 | border-color:#7A9437; 137 | border-style:solid; 138 | border-width:0 0 2px 0; 139 | } 140 | 141 | h3 { 142 | margin-top:30px; 143 | margin-bottom:2px; 144 | padding: 5 5 5 0; 145 | font-size: 24px; 146 | border-style:solid; 147 | border-width:0 0 2px 0; 148 | } 149 | 150 | h4 { 151 | margin-bottom:2px; 152 | margin-top:2px; 153 | font-size:medium; 154 | 155 | border-color:#7A9437; 156 | border-style:dashed; 157 | border-width:0 0 1px 0; 158 | } 159 | 160 | h5 { 161 | margin-bottom:2px; 162 | margin-top:2px; 163 | margin-left:20px; 164 | font-size:medium; 165 | } 166 | 167 | span.resolved { 168 | padding-left: 15px; 169 | font-weight: 500; 170 | font-size: small; 171 | } 172 | 173 | 174 | #content table { 175 | border-collapse:collapse; 176 | width:90%; 177 | margin:auto; 178 | margin-top: 5px; 179 | } 180 | #content thead { 181 | background-color:#CED4BD; 182 | border:1px solid #7A9437; 183 | } 184 | #content tbody { 185 | border-collapse:collapse; 186 | background-color:#FFFFFF; 187 | border:1px solid #7A9437; 188 | } 189 | 190 | #content th { 191 | font-family:monospace; 192 | border:1px solid #7A9437; 193 | padding:5px; 194 | } 195 | 196 | #content td { 197 | border:1px dotted #7A9437; 198 | padding:0 3 0 3; 199 | } 200 | 201 | #content table a { 202 | color:#7A9437; 203 | text-decoration:none; 204 | } 205 | 206 | #content table a:hover { 207 | background-color:#CED4BD; 208 | color:#7A9437; 209 | } 210 | 211 | 212 | 213 | table.deps { 214 | border-collapse:collapse; 215 | width:90%; 216 | margin:auto; 217 | margin-top: 5px; 218 | } 219 | 220 | table.deps thead { 221 | background-color:#CED4BD; 222 | border:1px solid #7A9437; 223 | } 224 | table.deps tbody { 225 | border-collapse:collapse; 226 | background-color:#FFFFFF; 227 | border:1px solid #7A9437; 228 | } 229 | 230 | table.deps th { 231 | font-family:monospace; 232 | border:1px solid #7A9437; 233 | padding:2; 234 | } 235 | 236 | table.deps td { 237 | border:1px dotted #7A9437; 238 | padding:0 3 0 3; 239 | } 240 | 241 | 242 | 243 | 244 | 245 | table.header { 246 | border:0; 247 | width:90%; 248 | margin:auto; 249 | margin-top: 5px; 250 | } 251 | 252 | table.header thead { 253 | border:0; 254 | } 255 | table.header tbody { 256 | border:0; 257 | } 258 | table.header tr { 259 | padding:0px; 260 | border:0; 261 | } 262 | table.header td { 263 | padding:0 3 0 3; 264 | border:0; 265 | } 266 | 267 | td.title { 268 | width:150px; 269 | margin-right:15px; 270 | 271 | font-size:small; 272 | font-weight:700; 273 | } 274 | 275 | td.title:first-letter { 276 | color:#7A9437; 277 | background-color:transparent; 278 | } 279 | 280 | -------------------------------------------------------------------------------- /collections/work_with_lists.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 前言\n", 8 | "在Scala中,List是一个高效的数据结构,尤其对于很多递归算法尤其重要。它可以容易在头部添加元素,也可以得到列表的尾部。" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## 列表的最后一个元素" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 1, 21 | "metadata": { 22 | "collapsed": false 23 | }, 24 | "outputs": [ 25 | { 26 | "data": { 27 | "text/plain": [ 28 | "\u001b[36mlist1\u001b[0m: \u001b[32mList\u001b[0m[\u001b[32mInt\u001b[0m] = \u001b[33mList\u001b[0m(\u001b[32m1\u001b[0m, \u001b[32m1\u001b[0m, \u001b[32m2\u001b[0m, \u001b[32m3\u001b[0m, \u001b[32m5\u001b[0m, \u001b[32m8\u001b[0m)" 29 | ] 30 | }, 31 | "metadata": {}, 32 | "output_type": "display_data" 33 | } 34 | ], 35 | "source": [ 36 | "val list1 = List(1, 1, 2, 3, 5, 8)" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 4, 42 | "metadata": { 43 | "collapsed": false 44 | }, 45 | "outputs": [ 46 | { 47 | "data": { 48 | "text/plain": [ 49 | "defined \u001b[32mfunction \u001b[36mlastBuildin\u001b[0m" 50 | ] 51 | }, 52 | "metadata": {}, 53 | "output_type": "display_data" 54 | } 55 | ], 56 | "source": [ 57 | "def lastBuildin[A](ls: List[A]): A = ls.last" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 5, 63 | "metadata": { 64 | "collapsed": false 65 | }, 66 | "outputs": [ 67 | { 68 | "data": { 69 | "text/plain": [ 70 | "defined \u001b[32mfunction \u001b[36mlastRecursive\u001b[0m" 71 | ] 72 | }, 73 | "metadata": {}, 74 | "output_type": "display_data" 75 | } 76 | ], 77 | "source": [ 78 | "def lastRecursive[A](ls: List[A]): A = ls match {\n", 79 | " case h :: Nil => h\n", 80 | " case _ :: tail => lastRecursive(tail)\n", 81 | " case _ => throw new NoSuchElementException\n", 82 | "}" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 6, 88 | "metadata": { 89 | "collapsed": false 90 | }, 91 | "outputs": [ 92 | { 93 | "data": { 94 | "text/plain": [ 95 | "\u001b[36mres3\u001b[0m: \u001b[32mInt\u001b[0m = \u001b[32m8\u001b[0m" 96 | ] 97 | }, 98 | "metadata": {}, 99 | "output_type": "display_data" 100 | } 101 | ], 102 | "source": [ 103 | "lastBuildin(list1)" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 7, 109 | "metadata": { 110 | "collapsed": false 111 | }, 112 | "outputs": [ 113 | { 114 | "data": { 115 | "text/plain": [ 116 | "\u001b[36mres4\u001b[0m: \u001b[32mInt\u001b[0m = \u001b[32m8\u001b[0m" 117 | ] 118 | }, 119 | "metadata": {}, 120 | "output_type": "display_data" 121 | } 122 | ], 123 | "source": [ 124 | "lastRecursive(list1)" 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "## 列表的倒数第二个元素" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 8, 137 | "metadata": { 138 | "collapsed": false 139 | }, 140 | "outputs": [ 141 | { 142 | "data": { 143 | "text/plain": [ 144 | "defined \u001b[32mfunction \u001b[36mpenultimateBuildin\u001b[0m" 145 | ] 146 | }, 147 | "metadata": {}, 148 | "output_type": "display_data" 149 | } 150 | ], 151 | "source": [ 152 | "def penultimateBuildin[A](ls: List[A]): A =\n", 153 | " if(ls.isEmpty) throw new NoSuchElementException\n", 154 | " else ls.init.last" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": 9, 160 | "metadata": { 161 | "collapsed": false 162 | }, 163 | "outputs": [ 164 | { 165 | "data": { 166 | "text/plain": [ 167 | "defined \u001b[32mfunction \u001b[36mpenultimateRecursive\u001b[0m" 168 | ] 169 | }, 170 | "metadata": {}, 171 | "output_type": "display_data" 172 | } 173 | ], 174 | "source": [ 175 | "def penultimateRecursive[A](ls: List[A]): A = ls match {\n", 176 | " case h :: _ :: Nil => h\n", 177 | " case _ :: tail => penultimateRecursive(tail)\n", 178 | " case _ => throw new NoSuchElementException\n", 179 | "}" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": 10, 185 | "metadata": { 186 | "collapsed": false 187 | }, 188 | "outputs": [ 189 | { 190 | "data": { 191 | "text/plain": [ 192 | "\u001b[36mres7\u001b[0m: \u001b[32mInt\u001b[0m = \u001b[32m5\u001b[0m" 193 | ] 194 | }, 195 | "metadata": {}, 196 | "output_type": "display_data" 197 | } 198 | ], 199 | "source": [ 200 | "penultimateBuildin(list1)" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 12, 206 | "metadata": { 207 | "collapsed": false 208 | }, 209 | "outputs": [ 210 | { 211 | "data": { 212 | "text/plain": [ 213 | "\u001b[36mres8\u001b[0m: \u001b[32mInt\u001b[0m = \u001b[32m5\u001b[0m" 214 | ] 215 | }, 216 | "metadata": {}, 217 | "output_type": "display_data" 218 | } 219 | ], 220 | "source": [ 221 | "penultimateRecursive(list1)" 222 | ] 223 | }, 224 | { 225 | "cell_type": "code", 226 | "execution_count": null, 227 | "metadata": { 228 | "collapsed": true 229 | }, 230 | "outputs": [], 231 | "source": [] 232 | } 233 | ], 234 | "metadata": { 235 | "kernelspec": { 236 | "display_name": "Scala 2.11", 237 | "language": "scala211", 238 | "name": "scala211" 239 | }, 240 | "language_info": { 241 | "codemirror_mode": "text/x-scala", 242 | "file_extension": ".scala", 243 | "mimetype": "text/x-scala", 244 | "name": "scala211", 245 | "pygments_lexer": "scala", 246 | "version": "2.11.6" 247 | } 248 | }, 249 | "nbformat": 4, 250 | "nbformat_minor": 0 251 | } 252 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.10-scala-tool.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /functional/combinators.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 软件复用组件\n", 8 | "成功的组件模型都依赖于非常简单的基础,这些基础使得组件能够创建、生成更加复杂的结构。\n", 9 | "\n", 10 | "面向对象编程从未建立过这种基础性、通用的标准,其中组件的基础单位是对象,但对象还不够底层。每个开发者都会为客户创造一个新的“标准”,没有任何团队能为客户应该有哪些字段达成一致,因为它们需要满足客户在不同场景下的不同需求,因而需要不同的数据和运算方式。\n", 11 | "\n", 12 | "在函数式编程语言的集合类型中,像List、VectorMap等,它们都共享一些共同的操作,这些操作大多定义在Seq这个抽象特征中。除了foreach操作外,所有操作都是纯净的高阶函数,没有副作用,且都接受函数作为参数,具体工作由该函数完成。这种高阶函数与离散数据中的组合器(combinator)概念非常接近。\n", 13 | "\n", 14 | "**我们可以将这些组合器串联起来,从而用很少的代码完成复杂的功能。对于特定问题,我们可以将数据和需要实现的行为分离。这与通常的面向对象编程的方法正好相反,面向对象总是将数据和行为绑定在一起。在自定义的类中创建所需逻辑的临时实现,是面向对象的典型做法**" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## 工资单计算器的例子" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 4, 27 | "metadata": { 28 | "collapsed": false 29 | }, 30 | "outputs": [ 31 | { 32 | "data": { 33 | "text/plain": [ 34 | "defined \u001b[32mclass \u001b[36mEmployee\u001b[0m" 35 | ] 36 | }, 37 | "metadata": {}, 38 | "output_type": "display_data" 39 | } 40 | ], 41 | "source": [ 42 | "case class Employee (\n", 43 | " name: String,\n", 44 | " title: String,\n", 45 | " annualSalary: Double,\n", 46 | " taxRate: Double,\n", 47 | " insurancePremiumsPerWeek: Double)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 5, 53 | "metadata": { 54 | "collapsed": false 55 | }, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/plain": [ 60 | "\u001b[36memployees\u001b[0m: \u001b[32mList\u001b[0m[\u001b[32mEmployee\u001b[0m] = \u001b[33mList\u001b[0m(\n", 61 | " \u001b[33mEmployee\u001b[0m(\u001b[32m\"Buck Trends\"\u001b[0m, \u001b[32m\"CEO\"\u001b[0m, \u001b[32m200000.0\u001b[0m, \u001b[32m0.25\u001b[0m, \u001b[32m100.0\u001b[0m),\n", 62 | " \u001b[33mEmployee\u001b[0m(\u001b[32m\"Cindy Banks\"\u001b[0m, \u001b[32m\"CFO\"\u001b[0m, \u001b[32m170000.0\u001b[0m, \u001b[32m0.22\u001b[0m, \u001b[32m120.0\u001b[0m),\n", 63 | " \u001b[33mEmployee\u001b[0m(\n", 64 | " \u001b[32m\"Joe Coder\"\u001b[0m,\n", 65 | " \u001b[32m\"Developer\"\u001b[0m,\n", 66 | " \u001b[32m130000.0\u001b[0m,\n", 67 | " \u001b[32m0.2\u001b[0m,\n", 68 | " \u001b[32m120.0\u001b[0m\n", 69 | " )\n", 70 | ")" 71 | ] 72 | }, 73 | "metadata": {}, 74 | "output_type": "display_data" 75 | } 76 | ], 77 | "source": [ 78 | "val employees = List(\n", 79 | " Employee(\"Buck Trends\", \"CEO\", 200000, 0.25, 100.0),\n", 80 | " Employee(\"Cindy Banks\", \"CFO\", 170000, 0.22, 120.0),\n", 81 | " Employee(\"Joe Coder\", \"Developer\", 130000, 0.20, 120.0)\n", 82 | ")" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "定义Employee类放置雇员的字段类型,实际应用中,这些数据可能从数据库中加载。Employee类型很简单,只需要定义少量行为,在经典的面向对象设计中,我们可能会给Employee添加很多行为,用于工资计算或实现其他域的逻辑。在这里所选择的设计提供了最佳的分离,同时这种设计非常简洁。如果Employee的结构发生变化,需要修改代码时,维护的成本非常小。" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 6, 95 | "metadata": { 96 | "collapsed": false 97 | }, 98 | "outputs": [ 99 | { 100 | "data": { 101 | "text/plain": [ 102 | "\u001b[36mnetPay\u001b[0m: \u001b[32mList\u001b[0m[(\u001b[32mEmployee\u001b[0m, \u001b[32mDouble\u001b[0m)] = \u001b[33mList\u001b[0m(\n", 103 | " \u001b[33m\u001b[0m(\n", 104 | " \u001b[33mEmployee\u001b[0m(\n", 105 | " \u001b[32m\"Buck Trends\"\u001b[0m,\n", 106 | " \u001b[32m\"CEO\"\u001b[0m,\n", 107 | " \u001b[32m200000.0\u001b[0m,\n", 108 | " \u001b[32m0.25\u001b[0m,\n", 109 | " \u001b[32m100.0\u001b[0m\n", 110 | " ),\n", 111 | " \u001b[32m2784.6153846153848\u001b[0m\n", 112 | " ),\n", 113 | " \u001b[33m\u001b[0m(\n", 114 | " \u001b[33mEmployee\u001b[0m(\n", 115 | " \u001b[32m\"Cindy Banks\"\u001b[0m,\n", 116 | " \u001b[32m\"CFO\"\u001b[0m,\n", 117 | "\u001b[33m...\u001b[0m" 118 | ] 119 | }, 120 | "metadata": {}, 121 | "output_type": "display_data" 122 | } 123 | ], 124 | "source": [ 125 | "// 计算每周工资单\n", 126 | "val netPay = employees map { e =>\n", 127 | " val net = (1.0-e.taxRate) * (e.annualSalary / 52.0) -\n", 128 | " e.insurancePremiumsPerWeek \n", 129 | " (e, net)\n", 130 | "}" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 8, 136 | "metadata": { 137 | "collapsed": false 138 | }, 139 | "outputs": [ 140 | { 141 | "name": "stdout", 142 | "output_type": "stream", 143 | "text": [ 144 | "** Paychecks:\n", 145 | " Buck Trends: 2784.62\n", 146 | " Cindy Banks: 2430.00\n", 147 | " Joe Coder: 1880.00\n" 148 | ] 149 | }, 150 | { 151 | "data": { 152 | "text/plain": [] 153 | }, 154 | "metadata": {}, 155 | "output_type": "display_data" 156 | } 157 | ], 158 | "source": [ 159 | "// 打印工资单\n", 160 | "println(\"** Paychecks:\")\n", 161 | "netPay foreach {\n", 162 | " case (e, net) => println(f\" ${e.name+':'}%-16s ${net}%10.2f\")\n", 163 | "}" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 9, 169 | "metadata": { 170 | "collapsed": false 171 | }, 172 | "outputs": [ 173 | { 174 | "data": { 175 | "text/plain": [ 176 | "\u001b[36mreport\u001b[0m: (\u001b[32mDouble\u001b[0m, \u001b[32mDouble\u001b[0m, \u001b[32mDouble\u001b[0m) = \u001b[33m\u001b[0m(\u001b[32m9615.384615384615\u001b[0m, \u001b[32m7094.615384615385\u001b[0m, \u001b[32m340.0\u001b[0m)" 177 | ] 178 | }, 179 | "metadata": {}, 180 | "output_type": "display_data" 181 | } 182 | ], 183 | "source": [ 184 | "// 生成报表\n", 185 | "val report = (netPay foldLeft (0.0, 0.0, 0.0)) {\n", 186 | " case ((totalSalary, totalNet, totalInsurance), (e, net)) =>\n", 187 | " (totalSalary + e.annualSalary / 52.0,\n", 188 | " totalNet + net,\n", 189 | " totalInsurance + e.insurancePremiumsPerWeek)\n", 190 | "}" 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": 10, 196 | "metadata": { 197 | "collapsed": false 198 | }, 199 | "outputs": [ 200 | { 201 | "name": "stdout", 202 | "output_type": "stream", 203 | "text": [ 204 | "\n", 205 | "** Report:\n", 206 | " Total Salary: 9615.38\n", 207 | " Total Net: 7094.62\n", 208 | " Total Insurance: 340.00\n" 209 | ] 210 | }, 211 | { 212 | "data": { 213 | "text/plain": [] 214 | }, 215 | "metadata": {}, 216 | "output_type": "display_data" 217 | } 218 | ], 219 | "source": [ 220 | "println(\"\\n** Report:\")\n", 221 | "println(f\" Total Salary: ${report._1}%10.2f\")\n", 222 | "println(f\" Total Net: ${report._2}%10.2f\")\n", 223 | "println(f\" Total Insurance: ${report._3}%10.2f\")" 224 | ] 225 | } 226 | ], 227 | "metadata": { 228 | "kernelspec": { 229 | "display_name": "Scala 2.11", 230 | "language": "scala211", 231 | "name": "scala211" 232 | }, 233 | "language_info": { 234 | "codemirror_mode": "text/x-scala", 235 | "file_extension": ".scala", 236 | "mimetype": "text/x-scala", 237 | "name": "scala211", 238 | "pygments_lexer": "scala", 239 | "version": "2.11.6" 240 | } 241 | }, 242 | "nbformat": 4, 243 | "nbformat_minor": 0 244 | } 245 | -------------------------------------------------------------------------------- /functional/functional_data_structure.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 函数式编程中的数据结构\n", 8 | "在函数式编程中,往往大量使用一些核心的数据结构和算法。相比于面向对象编程利用代码复用来减少冗余,函数式编程更倾向于编写简洁易复用的代码,因为语言将重点放在使用核心数据结构和算法实现业务逻辑上。\n", 9 | "\n", 10 | "函数式语言中每种集合类型都支持同一批无副作用的高阶函数,称为组合器(combinator),如map、filter、fold等。一旦你了解了这些组合器,你就可以根据自身对数据访问的需求及性能要求,选用合适的集合类型,用同样的组合器函数去操作数据。在所有的软件开发工作中,这些集合类型是代码复用与组合的最有效工具。" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "collapsed": true 17 | }, 18 | "source": [ 19 | "## 1 序列\n", 20 | "序列的元素时可以按特定的顺序访问的,scala.collection.Seq是一个trait,是所有可变或不可变序列类型的抽象,其子trait对应scala.collection.mutable.Seq和scala.collection.immutable.Seq。\n", 21 | "\n", 22 | "**推荐将Seq作为序列型数据结构的参数或作为返回值,因为这样,Seq的任何子类型都可以使用。**Seq使用+:方法来构造新的序列,使用++连接两个序列。" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 2, 28 | "metadata": { 29 | "collapsed": false 30 | }, 31 | "outputs": [ 32 | { 33 | "data": { 34 | "text/plain": [ 35 | "\u001b[36mseq1\u001b[0m: \u001b[32mSeq\u001b[0m[\u001b[32mString\u001b[0m] = \u001b[33mList\u001b[0m(\u001b[32m\"Programming\"\u001b[0m, \u001b[32m\"Scala\"\u001b[0m)\n", 36 | "\u001b[36mseq2\u001b[0m: \u001b[32mSeq\u001b[0m[\u001b[32mString\u001b[0m] = \u001b[33mList\u001b[0m(\u001b[32m\"People\"\u001b[0m, \u001b[32m\"should\"\u001b[0m, \u001b[32m\"read\"\u001b[0m)\n", 37 | "\u001b[36mseq3\u001b[0m: \u001b[32mSeq\u001b[0m[\u001b[32mString\u001b[0m] = \u001b[33mList\u001b[0m(\n", 38 | " \u001b[32m\"People\"\u001b[0m,\n", 39 | " \u001b[32m\"should\"\u001b[0m,\n", 40 | " \u001b[32m\"read\"\u001b[0m,\n", 41 | " \u001b[32m\"Programming\"\u001b[0m,\n", 42 | " \u001b[32m\"Scala\"\u001b[0m\n", 43 | ")" 44 | ] 45 | }, 46 | "metadata": {}, 47 | "output_type": "display_data" 48 | } 49 | ], 50 | "source": [ 51 | "val seq1 = Seq(\"Programming\", \"Scala\")\n", 52 | "val seq2 = \"People\" +: \"should\" +: \"read\" +: Seq.empty\n", 53 | "val seq3 = seq2 ++ seq1" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "可以考虑用immutable.Vector代替List,因为不可变Vector的所有操作都是O(1),而List对于那些需要访问头部以外元素的操作,都需要O(n)操作。" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "**有关预定义的讨论**\n", 68 | "\n", 69 | "为了鼓励程序员使用不可变的集合类型,Predef在暴露不可变集合类型时,不需要显示导入或使用全路径导入。但是Predef还将scala.collection.Seq导入到了当前作用域,该类型是可变集合类型和不可变集合类型共同的抽象特质,这使得传入的Seq类型实例可能是可变的,所以线程是不安全的。" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "### 1.1 运用包对象为Seq定义别名,覆盖原有别名定义\n", 77 | "为了使用scala.collection.immutable.Seq代替默认的scala.collection.Seq,使用包对象来解决:\n", 78 | "``` scala\n", 79 | "package fp\n", 80 | "package object datastructs {\n", 81 | " type Seq[+A] = scala.collection.immutable.Seq[A]\n", 82 | " val Seq = scala.collection.immutable.Seq\n", 83 | "}\n", 84 | "```\n", 85 | "package关键字也是包对象定义的一部分,在一个包中只能有一个包对象。最后,该文件的路径是src/main/scala/fp/datastructs/package.scala,这是一种常用的命名习惯。\n", 86 | "\n", 87 | "在包对象中,我们声明了**一个类型别名和一个val变量**。类型声明导入之后,使用Seq声明一个实例时,就需要使用scala.collection.immutable.Seq;val Seq的声明语句**将伴随对象引入作用域**,于是类似Seq(1,2,3,4)的语句就会触发scala.collection.immutable.Seq.apply方法的调用。" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "## 2 映射表\n", 95 | "映射表用来存储键值对,但不应将其余很多数据结构的map方法混淆。映射表与map方法有一定程度的相似,前者每个键都对应一个值,后者每个输入元素都产生一个输出元素。" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 3, 101 | "metadata": { 102 | "collapsed": false 103 | }, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "\u001b[36mstateCapitals\u001b[0m: \u001b[32mMap\u001b[0m[\u001b[32mString\u001b[0m, \u001b[32mString\u001b[0m] = \u001b[33mMap\u001b[0m(\n", 109 | " \u001b[32m\"Alabama\"\u001b[0m -> \u001b[32m\"Montgomery\"\u001b[0m,\n", 110 | " \u001b[32m\"Alaska\"\u001b[0m -> \u001b[32m\"Juneau\"\u001b[0m,\n", 111 | " \u001b[32m\"Wyoming\"\u001b[0m -> \u001b[32m\"Cheyenne\"\u001b[0m\n", 112 | ")" 113 | ] 114 | }, 115 | "metadata": {}, 116 | "output_type": "display_data" 117 | } 118 | ], 119 | "source": [ 120 | "val stateCapitals = Map(\n", 121 | " \"Alabama\" -> \"Montgomery\",\n", 122 | " \"Alaska\" -> \"Juneau\",\n", 123 | " \"Wyoming\" -> \"Cheyenne\"\n", 124 | ")" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 4, 130 | "metadata": { 131 | "collapsed": false 132 | }, 133 | "outputs": [ 134 | { 135 | "data": { 136 | "text/plain": [ 137 | "\u001b[36mlengths\u001b[0m: \u001b[32mMap\u001b[0m[\u001b[32mString\u001b[0m, \u001b[32mInt\u001b[0m] = \u001b[33mMap\u001b[0m(\n", 138 | " \u001b[32m\"Alabama\"\u001b[0m -> \u001b[32m10\u001b[0m,\n", 139 | " \u001b[32m\"Alaska\"\u001b[0m -> \u001b[32m6\u001b[0m,\n", 140 | " \u001b[32m\"Wyoming\"\u001b[0m -> \u001b[32m8\u001b[0m\n", 141 | ")" 142 | ] 143 | }, 144 | "metadata": {}, 145 | "output_type": "display_data" 146 | } 147 | ], 148 | "source": [ 149 | "val lengths = stateCapitals map {\n", 150 | " kv => (kv._1, kv._2.length)\n", 151 | "}" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 5, 157 | "metadata": { 158 | "collapsed": false 159 | }, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "text/plain": [ 164 | "\u001b[36mcaps\u001b[0m: \u001b[32mMap\u001b[0m[\u001b[32mString\u001b[0m, \u001b[32mString\u001b[0m] = \u001b[33mMap\u001b[0m(\n", 165 | " \u001b[32m\"Alabama\"\u001b[0m -> \u001b[32m\"MONTGOMERY\"\u001b[0m,\n", 166 | " \u001b[32m\"Alaska\"\u001b[0m -> \u001b[32m\"JUNEAU\"\u001b[0m,\n", 167 | " \u001b[32m\"Wyoming\"\u001b[0m -> \u001b[32m\"CHEYENNE\"\u001b[0m\n", 168 | ")" 169 | ] 170 | }, 171 | "metadata": {}, 172 | "output_type": "display_data" 173 | } 174 | ], 175 | "source": [ 176 | "val caps = stateCapitals map {\n", 177 | " case (k, v) => (k, v.toUpperCase)\n", 178 | "}" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": 6, 184 | "metadata": { 185 | "collapsed": false 186 | }, 187 | "outputs": [ 188 | { 189 | "data": { 190 | "text/plain": [ 191 | "\u001b[36mstateCapitals2\u001b[0m: \u001b[32mMap\u001b[0m[\u001b[32mString\u001b[0m, \u001b[32mString\u001b[0m] = \u001b[33mMap\u001b[0m(\n", 192 | " \u001b[32m\"Alabama\"\u001b[0m -> \u001b[32m\"Montgomery\"\u001b[0m,\n", 193 | " \u001b[32m\"Alaska\"\u001b[0m -> \u001b[32m\"Juneau\"\u001b[0m,\n", 194 | " \u001b[32m\"Wyoming\"\u001b[0m -> \u001b[32m\"Cheyenne\"\u001b[0m,\n", 195 | " \u001b[32m\"Virginia\"\u001b[0m -> \u001b[32m\"Richmond\"\u001b[0m\n", 196 | ")" 197 | ] 198 | }, 199 | "metadata": {}, 200 | "output_type": "display_data" 201 | } 202 | ], 203 | "source": [ 204 | "val stateCapitals2 = stateCapitals + (\"Virginia\" -> \"Richmond\")" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "metadata": {}, 210 | "source": [ 211 | "key -> value的语法形式实际上用库中的隐式转换实现的,实际调用了Map.apply方法。Map.apply方法的参数为一个两元素的元组(键值对)。" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": {}, 217 | "source": [ 218 | "## 3 集合\n", 219 | "集合是无序集合类型的一个例子,所以集合不是序列。集合要求元素具有唯一性。" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": 7, 225 | "metadata": { 226 | "collapsed": false 227 | }, 228 | "outputs": [ 229 | { 230 | "data": { 231 | "text/plain": [ 232 | "\u001b[36mstates\u001b[0m: \u001b[32mSet\u001b[0m[\u001b[32mString\u001b[0m] = \u001b[33mSet\u001b[0m(\u001b[32m\"Alabama\"\u001b[0m, \u001b[32m\"Alaska\"\u001b[0m, \u001b[32m\"Wyoming\"\u001b[0m)" 233 | ] 234 | }, 235 | "metadata": {}, 236 | "output_type": "display_data" 237 | } 238 | ], 239 | "source": [ 240 | "val states = Set(\"Alabama\", \"Alaska\", \"Wyoming\")" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": 8, 246 | "metadata": { 247 | "collapsed": false 248 | }, 249 | "outputs": [ 250 | { 251 | "data": { 252 | "text/plain": [ 253 | "\u001b[36mlengths\u001b[0m: \u001b[32mSet\u001b[0m[\u001b[32mInt\u001b[0m] = \u001b[33mSet\u001b[0m(\u001b[32m7\u001b[0m, \u001b[32m6\u001b[0m)" 254 | ] 255 | }, 256 | "metadata": {}, 257 | "output_type": "display_data" 258 | } 259 | ], 260 | "source": [ 261 | "val lengths = states map (st => st.length)" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 9, 267 | "metadata": { 268 | "collapsed": false 269 | }, 270 | "outputs": [ 271 | { 272 | "data": { 273 | "text/plain": [ 274 | "\u001b[36mstates2\u001b[0m: \u001b[32mSet\u001b[0m[\u001b[32mString\u001b[0m] = \u001b[33mSet\u001b[0m(\n", 275 | " \u001b[32m\"Alaska\"\u001b[0m,\n", 276 | " \u001b[32m\"Alabama\"\u001b[0m,\n", 277 | " \u001b[32m\"New York\"\u001b[0m,\n", 278 | " \u001b[32m\"Illinois\"\u001b[0m,\n", 279 | " \u001b[32m\"Wyoming\"\u001b[0m\n", 280 | ")" 281 | ] 282 | }, 283 | "metadata": {}, 284 | "output_type": "display_data" 285 | } 286 | ], 287 | "source": [ 288 | "val states2 = states + (\"New York\", \"Illinois\")" 289 | ] 290 | } 291 | ], 292 | "metadata": { 293 | "kernelspec": { 294 | "display_name": "Scala 2.11", 295 | "language": "scala211", 296 | "name": "scala211" 297 | }, 298 | "language_info": { 299 | "codemirror_mode": "text/x-scala", 300 | "file_extension": ".scala", 301 | "mimetype": "text/x-scala", 302 | "name": "scala211", 303 | "pygments_lexer": "scala", 304 | "version": "2.11.6" 305 | } 306 | }, 307 | "nbformat": 4, 308 | "nbformat_minor": 0 309 | } 310 | -------------------------------------------------------------------------------- /implicits/implicit_conversion.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "collapsed": true 7 | }, 8 | "source": [ 9 | "## 1 隐式转换\n", 10 | "隐式转换(也称为隐式视图),指把一种类型自动转换到另一种类型,以符合表达式的要求。" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": { 17 | "collapsed": false 18 | }, 19 | "outputs": [ 20 | { 21 | "data": { 22 | "text/plain": [ 23 | "defined \u001b[32mfunction \u001b[36mfoo\u001b[0m" 24 | ] 25 | }, 26 | "metadata": {}, 27 | "output_type": "display_data" 28 | } 29 | ], 30 | "source": [ 31 | "def foo(msg: String) = println(msg)" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 2, 37 | "metadata": { 38 | "collapsed": false 39 | }, 40 | "outputs": [ 41 | { 42 | "ename": "", 43 | "evalue": "", 44 | "output_type": "error", 45 | "traceback": [ 46 | "Compilation Failed", 47 | "\u001b[31mMain.scala:51: type mismatch;", 48 | " found : Int(5)", 49 | " required: String\r", 50 | "foo(5)\r", 51 | " ^\u001b[0m" 52 | ] 53 | } 54 | ], 55 | "source": [ 56 | "foo(5)" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "由于类型不匹配,出现编译失败的错误提示。我们需要进行隐式转换来完成调用。" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 3, 69 | "metadata": { 70 | "collapsed": false 71 | }, 72 | "outputs": [ 73 | { 74 | "data": { 75 | "text/plain": [ 76 | "defined \u001b[32mfunction \u001b[36mintToString\u001b[0m" 77 | ] 78 | }, 79 | "metadata": {}, 80 | "output_type": "display_data" 81 | } 82 | ], 83 | "source": [ 84 | "implicit def intToString(x: Int) = x.toString" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 4, 90 | "metadata": { 91 | "collapsed": false 92 | }, 93 | "outputs": [ 94 | { 95 | "name": "stdout", 96 | "output_type": "stream", 97 | "text": [ 98 | "5\r\n" 99 | ] 100 | }, 101 | { 102 | "data": { 103 | "text/plain": [] 104 | }, 105 | "metadata": {}, 106 | "output_type": "display_data" 107 | } 108 | ], 109 | "source": [ 110 | "foo(5)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "### 1.1 以->方法为例" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 5, 123 | "metadata": { 124 | "collapsed": false 125 | }, 126 | "outputs": [ 127 | { 128 | "data": { 129 | "text/plain": [ 130 | "\u001b[36mres3\u001b[0m: \u001b[32mMap\u001b[0m[\u001b[32mString\u001b[0m, \u001b[32mInt\u001b[0m] = \u001b[33mMap\u001b[0m(\u001b[32m\"one\"\u001b[0m -> \u001b[32m1\u001b[0m, \u001b[32m\"two\"\u001b[0m -> \u001b[32m2\u001b[0m)" 131 | ] 132 | }, 133 | "metadata": {}, 134 | "output_type": "display_data" 135 | } 136 | ], 137 | "source": [ 138 | "Map(\"one\" -> 1, \"two\" -> 2)" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "上面的方法调用了Map.apply方法,而该方法的输入时一组可变数量的pair对象:\n", 146 | "``` scala\n", 147 | "def apply[A, B](elems: (A, B)*): Map[A, B]\n", 148 | "```\n", 149 | "这里并没有见到->方法的使用,所以其实->方法使用了隐式转换。\n", 150 | "\n", 151 | "通过隐式转换,将任意两种类型值之间插入函数->,将表达式a -> b转换为元组(a, b)。" 152 | ] 153 | }, 154 | { 155 | "cell_type": "markdown", 156 | "metadata": {}, 157 | "source": [ 158 | "如果我们为所有可能作为元组首元素的类型都添加->方法肯定不现实。定义该方法的技巧是使用一个具有->方法的“封装”对象,Scala在Predef对象中定义了该对象:" 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "``` scala\n", 166 | "implicit final class ArrowAssoc[A](private val self: A) extends AnyVal {\n", 167 | " @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y)\n", 168 | " def →[B](y: B): Tuple2[A, B] = ->(y)\n", 169 | "}\n", 170 | "```" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "我们可以依照上面的定义来构造Map对象:" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 6, 183 | "metadata": { 184 | "collapsed": false 185 | }, 186 | "outputs": [ 187 | { 188 | "data": { 189 | "text/plain": [ 190 | "\u001b[36mres4\u001b[0m: \u001b[32mMap\u001b[0m[\u001b[32mString\u001b[0m, \u001b[32mInt\u001b[0m] = \u001b[33mMap\u001b[0m(\u001b[32m\"one\"\u001b[0m -> \u001b[32m1\u001b[0m, \u001b[32m\"two\"\u001b[0m -> \u001b[32m2\u001b[0m)" 191 | ] 192 | }, 193 | "metadata": {}, 194 | "output_type": "display_data" 195 | } 196 | ], 197 | "source": [ 198 | "Map(new ArrowAssoc(\"one\") -> 1, new ArrowAssoc(\"two\") -> 2)" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "由于ArrowAssoc类被声明为implicit类,因此编译器将执行下列逻辑:\n", 206 | "1. 编译器发现我们试图对String对象执行->方法\n", 207 | "2. 有String未定义->方法,编译器将检查当前作用域中是否存在定义了该方法的隐式转换\n", 208 | "3. 编译器发现了ArrowAssoc类\n", 209 | "4. 编译器将创建ArrowAssoc对象,并向其传入one字符串\n", 210 | "5. 编译器将解析表达式中的-> 1部分代码,并确认了整个表达式的类型与Map.apply方法的预期类型相吻合,即两者均为pair实例" 211 | ] 212 | }, 213 | { 214 | "cell_type": "markdown", 215 | "metadata": {}, 216 | "source": [ 217 | "### 1.2 隐式转换的查询规则\n", 218 | "能够执行隐式转换的只有两类:**构造方法中只接受单一参数的类型或者是只接受单一参数的方法**。\n", 219 | "\n", 220 | "从Scala 2.10以后,隐式方法变为Scala的可选特性,在使用时要通过`import scala.language.implicitConversions`开启这一特性,也可以使用全局的编译器选项`-language: implicitConversions`开启该特性。" 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": {}, 226 | "source": [ 227 | "编译器进行查找和使用隐式转换方法时的查询规则:\n", 228 | "- (1) 假如调用的对象和方法成功通过了组合类型检查,那么类型转换不会被执行\n", 229 | "- (2) 编译器只会考虑使用implicit关键字的类和方法\n", 230 | "- (3) 编译器只会考虑当前作用域内的隐式类、隐式方法,以及目标类型的伴生对象中定义的隐式方法\n", 231 | "- (4) 隐式方法无法串行处理,我们无法通过一个中间类型,使用串行的隐式方法将起始类型转换成目标类型。编译器执行隐式转换时只会考虑那些接受单一类型实例输入且返回目标类型实例的方法\n", 232 | "- (5) 假如当前适用多条隐式方法,那么将不会执行转换操作。编译器要求有且必须只有一条满足条件的隐式方法,以免产生二义性" 233 | ] 234 | }, 235 | { 236 | "cell_type": "markdown", 237 | "metadata": { 238 | "collapsed": true 239 | }, 240 | "source": [ 241 | "### 1.3 构建字符串插入器的例子\n", 242 | "Scala会提供一些内置的方法通过插入方式对字符串进行格式化,例如`s\"Hello, ${name}\"`,Scala编译器会查找scala.StringContext的s方法,将其转换成`StringContext(\"Hello, \", \"\").s(name)`。\n", 243 | "\n", 244 | "传递给StringContext.apply方法的参数是${...}表达式中抽取出的各个部分,传递给s从参数则是抽取后的表达式。" 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": {}, 250 | "source": [ 251 | "下面,我们通过隐式转换为StringContext添加新的方法,对其进行扩展,定义新的插入器。编写一个将简单JSON字符串转换为scala.util.parsing.JSONObject对象的插入器(该插入器功能简单,只处理扁平的JSON表达式)。" 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": 7, 257 | "metadata": { 258 | "collapsed": false 259 | }, 260 | "outputs": [ 261 | { 262 | "data": { 263 | "text/plain": [] 264 | }, 265 | "metadata": {}, 266 | "output_type": "display_data" 267 | } 268 | ], 269 | "source": [ 270 | "// Scala 2.11中,json包被放置在一个独立的解析器-组合器库中,这里需要加载jar包\n", 271 | "load.jar(\"D:\\\\scala\\\\lib\\\\scala-parser-combinators_2.11-1.0.4.jar\")" 272 | ] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "execution_count": 8, 277 | "metadata": { 278 | "collapsed": false 279 | }, 280 | "outputs": [ 281 | { 282 | "data": { 283 | "text/plain": [ 284 | "\u001b[32mimport \u001b[36mscala.util.parsing.json._\u001b[0m\n", 285 | "defined \u001b[32mobject \u001b[36mInterpolators\u001b[0m" 286 | ] 287 | }, 288 | "metadata": {}, 289 | "output_type": "display_data" 290 | } 291 | ], 292 | "source": [ 293 | "import scala.util.parsing.json._\n", 294 | "\n", 295 | "object Interpolators {\n", 296 | " implicit class jsonForStringContext(val sc: StringContext) { //为了限制隐式类的作用域,必须在对象内定义隐式类\n", 297 | " def json(values: Any*): JSONObject = { //该方法输入字符串中嵌套的参数,返回JSONObject对象\n", 298 | " val keyRE = \"\"\"^[\\s{,]*(\\S+):\\s*\"\"\".r //抽取key名称的正则表达式\n", 299 | " val keys = sc.parts map { \n", 300 | " case keyRE(key) => key\n", 301 | " case str => str\n", 302 | " }\n", 303 | " val kvs = keys zip values // 将key和value压缩成键值对集合\n", 304 | " JSONObject(kvs.toMap) //使用键值对构成Map对象,并构造JSONObject对象\n", 305 | " }\n", 306 | " }\n", 307 | "}" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 9, 313 | "metadata": { 314 | "collapsed": false 315 | }, 316 | "outputs": [ 317 | { 318 | "name": "stdout", 319 | "output_type": "stream", 320 | "text": [ 321 | "{\"name\" : \"Dean Wampler\", \"book\" : \"Programming Scala, Second Edition\"}\n" 322 | ] 323 | }, 324 | { 325 | "data": { 326 | "text/plain": [ 327 | "\u001b[32mimport \u001b[36mInterpolators._\u001b[0m\n", 328 | "\u001b[36mname\u001b[0m: \u001b[32mString\u001b[0m = \u001b[32m\"Dean Wampler\"\u001b[0m\n", 329 | "\u001b[36mbook\u001b[0m: \u001b[32mString\u001b[0m = \u001b[32m\"Programming Scala, Second Edition\"\u001b[0m\n", 330 | "\u001b[36mjsonobj\u001b[0m: \u001b[32mJSONObject\u001b[0m = \u001b[33mJSONObject\u001b[0m(\n", 331 | " \u001b[33mMap\u001b[0m(\u001b[32m\"name\"\u001b[0m -> Dean Wampler, \u001b[32m\"book\"\u001b[0m -> Programming Scala, Second Edition)\n", 332 | ")" 333 | ] 334 | }, 335 | "metadata": {}, 336 | "output_type": "display_data" 337 | } 338 | ], 339 | "source": [ 340 | "import Interpolators._\n", 341 | "\n", 342 | "val name = \"Dean Wampler\"\n", 343 | "val book = \"Programming Scala, Second Edition\"\n", 344 | "val jsonobj = json\"{name: $name, book: $book}\"\n", 345 | "println(jsonobj)" 346 | ] 347 | } 348 | ], 349 | "metadata": { 350 | "kernelspec": { 351 | "display_name": "Scala 2.11", 352 | "language": "scala211", 353 | "name": "scala211" 354 | }, 355 | "language_info": { 356 | "codemirror_mode": "text/x-scala", 357 | "file_extension": ".scala", 358 | "mimetype": "text/x-scala", 359 | "name": "scala211", 360 | "pygments_lexer": "scala", 361 | "version": "2.11.6" 362 | } 363 | }, 364 | "nbformat": 4, 365 | "nbformat_minor": 0 366 | } 367 | -------------------------------------------------------------------------------- /concurrency/shapes/target/resolution-cache/reports/default-shapes_2.11-scala-tool.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /concurrency/Rendering_Example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 模拟场景渲染过程中驱动actor和绘图actor的信息交互过程" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "本例将表示几何图形的一组类的实例发送给actor,该actor将这组实例绘制到显示屏上。像是渲染工厂(rendering farm)在为动画生成场景。一旦场景渲染完毕,构成的场景的几何图形便会被发送给某一actor进行展示。" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "metadata": { 21 | "collapsed": false 22 | }, 23 | "outputs": [ 24 | { 25 | "data": { 26 | "text/plain": [ 27 | "defined \u001b[32mclass \u001b[36mPoint\u001b[0m\n", 28 | "defined \u001b[32mclass \u001b[36mShape\u001b[0m\n", 29 | "defined \u001b[32mclass \u001b[36mCircle\u001b[0m\n", 30 | "defined \u001b[32mclass \u001b[36mRectangle\u001b[0m\n", 31 | "defined \u001b[32mclass \u001b[36mTriangle\u001b[0m" 32 | ] 33 | }, 34 | "metadata": {}, 35 | "output_type": "display_data" 36 | } 37 | ], 38 | "source": [ 39 | "case class Point(x: Double = 0.0, y: Double = 0.0)\n", 40 | "\n", 41 | "abstract class Shape() {\n", 42 | " // draw方法接受一个函数参数\n", 43 | " // 每个图形对象都会将自己的字符格式传给函数f,由f完成绘制工作\n", 44 | " def draw(f: String => Unit): Unit = f(s\"draw: ${this.toString}\")\n", 45 | "}\n", 46 | "\n", 47 | "case class Circle(center: Point, radius: Double) extends Shape\n", 48 | "case class Rectangle(lowerLeft: Point, height: Double, width: Double) extends Shape\n", 49 | "case class Triangle(point1: Point, point2: Point, point3: Point) extends Shape" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "样本类(case class)让编译器自动生成很多方法,比如String、equals和hashCode方法。编译器还会为样本类同时生成一个伴生对象。" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 2, 62 | "metadata": { 63 | "collapsed": false 64 | }, 65 | "outputs": [ 66 | { 67 | "data": { 68 | "text/plain": [ 69 | "\u001b[36mp20\u001b[0m: \u001b[32mPoint\u001b[0m = \u001b[33mPoint\u001b[0m(\u001b[32m2.0\u001b[0m, \u001b[32m0.0\u001b[0m)\n", 70 | "\u001b[36mp20b\u001b[0m: \u001b[32mPoint\u001b[0m = \u001b[33mPoint\u001b[0m(\u001b[32m2.0\u001b[0m, \u001b[32m0.0\u001b[0m)\n", 71 | "\u001b[36mp02\u001b[0m: \u001b[32mPoint\u001b[0m = \u001b[33mPoint\u001b[0m(\u001b[32m0.0\u001b[0m, \u001b[32m2.0\u001b[0m)" 72 | ] 73 | }, 74 | "metadata": {}, 75 | "output_type": "display_data" 76 | } 77 | ], 78 | "source": [ 79 | "// Scala调用生成的equals方法来判断==这样的逻辑比较\n", 80 | "val p20 = new Point(2.0)\n", 81 | "val p20b = new Point(2.0)\n", 82 | "val p02 = new Point(y = 2.0)" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 3, 88 | "metadata": { 89 | "collapsed": false 90 | }, 91 | "outputs": [ 92 | { 93 | "data": { 94 | "text/plain": [ 95 | "\u001b[36mres2\u001b[0m: \u001b[32mBoolean\u001b[0m = false" 96 | ] 97 | }, 98 | "metadata": {}, 99 | "output_type": "display_data" 100 | } 101 | ], 102 | "source": [ 103 | "p20 == p02" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 4, 109 | "metadata": { 110 | "collapsed": false 111 | }, 112 | "outputs": [ 113 | { 114 | "data": { 115 | "text/plain": [ 116 | "\u001b[36mres3\u001b[0m: \u001b[32mBoolean\u001b[0m = true" 117 | ] 118 | }, 119 | "metadata": {}, 120 | "output_type": "display_data" 121 | } 122 | ], 123 | "source": [ 124 | "p20 == p20b" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 5, 130 | "metadata": { 131 | "collapsed": false 132 | }, 133 | "outputs": [ 134 | { 135 | "data": { 136 | "text/plain": [ 137 | "\u001b[36mp1\u001b[0m: \u001b[32mPoint\u001b[0m = \u001b[33mPoint\u001b[0m(\u001b[32m1.0\u001b[0m, \u001b[32m2.0\u001b[0m)" 138 | ] 139 | }, 140 | "metadata": {}, 141 | "output_type": "display_data" 142 | } 143 | ], 144 | "source": [ 145 | "// 使用Point伴生类的apply方法\n", 146 | "\n", 147 | "val p1 = Point.apply(1.0, 2.0)" 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": {}, 153 | "source": [ 154 | "Point.apply是构造Point对象的工厂方法,调用该方法就好像不通过new关键字调用Point的构造器一样。\n", 155 | "``` scala\n", 156 | "object Point {\n", 157 | " def apply(x: Double = 0.0, y: Double = 0.0) = new Point(x, y)\n", 158 | " ...\n", 159 | "}\n", 160 | "```" 161 | ] 162 | }, 163 | { 164 | "cell_type": "markdown", 165 | "metadata": {}, 166 | "source": [ 167 | "以上定义好了形状类型,接下来回到actor上" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 6, 173 | "metadata": { 174 | "collapsed": false 175 | }, 176 | "outputs": [ 177 | { 178 | "data": { 179 | "text/plain": [ 180 | "defined \u001b[32mobject \u001b[36mMessages\u001b[0m" 181 | ] 182 | }, 183 | "metadata": {}, 184 | "output_type": "display_data" 185 | } 186 | ], 187 | "source": [ 188 | "object Messages {\n", 189 | " object Exit\n", 190 | " object Finished\n", 191 | " case class Response(message: String)\n", 192 | "}" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 7, 198 | "metadata": { 199 | "collapsed": false 200 | }, 201 | "outputs": [ 202 | { 203 | "data": { 204 | "text/plain": [] 205 | }, 206 | "metadata": {}, 207 | "output_type": "display_data" 208 | } 209 | ], 210 | "source": [ 211 | "load.jar(\"D:\\\\scala\\\\lib\\\\akka-actor_2.11-2.3.10.jar\")" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 8, 217 | "metadata": { 218 | "collapsed": false 219 | }, 220 | "outputs": [ 221 | { 222 | "data": { 223 | "text/plain": [ 224 | "\u001b[32mimport \u001b[36makka.actor.Actor\u001b[0m" 225 | ] 226 | }, 227 | "metadata": {}, 228 | "output_type": "display_data" 229 | } 230 | ], 231 | "source": [ 232 | "import akka.actor.Actor" 233 | ] 234 | }, 235 | { 236 | "cell_type": "markdown", 237 | "metadata": {}, 238 | "source": [ 239 | "此处定义了一个actor类,用于绘制图形。实现了抽象方法Actor.receive,该方法是Actor的子类必须实现的方法,定义了如何处理接收到的消息。" 240 | ] 241 | }, 242 | { 243 | "cell_type": "code", 244 | "execution_count": 9, 245 | "metadata": { 246 | "collapsed": false 247 | }, 248 | "outputs": [ 249 | { 250 | "data": { 251 | "text/plain": [ 252 | "defined \u001b[32mclass \u001b[36mShapesDrawingActor\u001b[0m" 253 | ] 254 | }, 255 | "metadata": {}, 256 | "output_type": "display_data" 257 | } 258 | ], 259 | "source": [ 260 | "class ShapesDrawingActor extends Actor {\n", 261 | " import Messages._\n", 262 | " \n", 263 | " def receive = {\n", 264 | " case s: Shape =>\n", 265 | " s.draw(str => println(s\"ShapesDrawingActor: $str\"))\n", 266 | " sender ! Response(s\"ShapesDrawingActor: $s drawn\")\n", 267 | " case Exit =>\n", 268 | " println(s\"ShapesDrawingActor: exiting...\")\n", 269 | " sender ! Finished\n", 270 | " case unexpected => //default. Equivalent to \"unexpected: Any\"\n", 271 | " val response = Response(s\"Error: Unknown message: $unexpected\")\n", 272 | " println(s\"ShapesDrawingActor: $response\")\n", 273 | " sender ! response\n", 274 | " }\n", 275 | "}" 276 | ] 277 | }, 278 | { 279 | "cell_type": "markdown", 280 | "metadata": {}, 281 | "source": [ 282 | "receive是偏函数,接受单一的Any类型参数并返回Unit值。由于该函数返回Unit对象,因此函数体一定会产生副作用。由于actor系统采用了异步消息机制,它必须依靠副作用。通常由于传递消息后无法返回任何消息,代码块中便会发送一些其他消息,包括给发送者的返回消息。\n", 283 | "\n", 284 | "偏函数中仅包含了一些case子句,对传递给函数的消息执行模型匹配。receive方法会尝试将接受到的各条消息与编写的模式匹配表达式进行匹配,并执行最先被匹配上的表达式。\n", 285 | "\n", 286 | "Actor.sender函数返回了actor发送消息接收方的对象引用,而!方法用于发送异步消息。" 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": 10, 292 | "metadata": { 293 | "collapsed": false 294 | }, 295 | "outputs": [ 296 | { 297 | "data": { 298 | "text/plain": [ 299 | "\u001b[32mimport \u001b[36makka.actor.{Props, ActorRef, ActorSystem}\u001b[0m" 300 | ] 301 | }, 302 | "metadata": {}, 303 | "output_type": "display_data" 304 | } 305 | ], 306 | "source": [ 307 | "import akka.actor.{Props, ActorRef, ActorSystem}" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 11, 313 | "metadata": { 314 | "collapsed": false 315 | }, 316 | "outputs": [ 317 | { 318 | "data": { 319 | "text/plain": [ 320 | "defined \u001b[32mobject \u001b[36mStart\u001b[0m" 321 | ] 322 | }, 323 | "metadata": {}, 324 | "output_type": "display_data" 325 | } 326 | ], 327 | "source": [ 328 | "object Start" 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": 21, 334 | "metadata": { 335 | "collapsed": false 336 | }, 337 | "outputs": [ 338 | { 339 | "data": { 340 | "text/plain": [ 341 | "defined \u001b[32mclass \u001b[36mShapesDrawingDriver\u001b[0m" 342 | ] 343 | }, 344 | "metadata": {}, 345 | "output_type": "display_data" 346 | } 347 | ], 348 | "source": [ 349 | "class ShapesDrawingDriver(drawerActor: ActorRef) extends Actor {\n", 350 | " import Messages._\n", 351 | " \n", 352 | " def receive = {\n", 353 | " case Start =>\n", 354 | " drawerActor ! Circle(Point(0.0, 0.0), 1.0)\n", 355 | " drawerActor ! Rectangle(Point(0.0, 0.0), 2, 5)\n", 356 | " drawerActor ! 3.14159\n", 357 | " drawerActor ! Triangle(Point(0.0, 0.0), Point(2.0, 0.0), Point(1.0, 2.0))\n", 358 | " drawerActor ! Exit\n", 359 | " case Finished =>\n", 360 | " println(s\"ShapesDrawingDriver: cleaning up...\")\n", 361 | " context.system.shutdown()\n", 362 | " case response: Response =>\n", 363 | " println(\"ShapesDrawingDriver: Response =\" + response)\n", 364 | " case unexpected =>\n", 365 | " println(\"ShapesDrawingDriver: ERROR: Receive an unexpected message =\" + unexpected)\n", 366 | " }\n", 367 | "}" 368 | ] 369 | }, 370 | { 371 | "cell_type": "markdown", 372 | "metadata": {}, 373 | "source": [ 374 | "接下来是驱动应用的主方法,首先构建一个akka.actor.ActorSystem对象和两个actor对象,然后将ShapesDrawingActor对象的引用传递给ShapesDrawingDriver,最后向驱动对象发送Start命令,启动应用。" 375 | ] 376 | }, 377 | { 378 | "cell_type": "code", 379 | "execution_count": 22, 380 | "metadata": { 381 | "collapsed": false 382 | }, 383 | "outputs": [ 384 | { 385 | "data": { 386 | "text/plain": [ 387 | "defined \u001b[32mobject \u001b[36mShapesDrawingApp\u001b[0m" 388 | ] 389 | }, 390 | "metadata": {}, 391 | "output_type": "display_data" 392 | } 393 | ], 394 | "source": [ 395 | "object ShapesDrawingApp extends App{\n", 396 | " val system = ActorSystem(\"DrawingActorSystem\")\n", 397 | " val drawer = system.actorOf(Props(new ShapesDrawingActor), \"drawingActor\")\n", 398 | " val driver = system.actorOf(Props(new ShapesDrawingDriver(drawer)), \"drawingService\")\n", 399 | " driver ! Start\n", 400 | " system.shutdown\n", 401 | "}" 402 | ] 403 | }, 404 | { 405 | "cell_type": "markdown", 406 | "metadata": {}, 407 | "source": [ 408 | "最后结果如图:\n", 409 | "![](images/shapes_result.jpg)" 410 | ] 411 | } 412 | ], 413 | "metadata": { 414 | "kernelspec": { 415 | "display_name": "Scala 2.11", 416 | "language": "scala211", 417 | "name": "scala211" 418 | }, 419 | "language_info": { 420 | "codemirror_mode": "text/x-scala", 421 | "file_extension": ".scala", 422 | "mimetype": "text/x-scala", 423 | "name": "scala211", 424 | "pygments_lexer": "scala", 425 | "version": "2.11.6" 426 | } 427 | }, 428 | "nbformat": 4, 429 | "nbformat_minor": 0 430 | } 431 | -------------------------------------------------------------------------------- /implicits/implicit_parameter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 隐式转换系统\n", 8 | "Scala的隐式转换系统提供了一套定义良好的查找机制,让编译器能够调整代码。当用Scala写代码时可以故意漏掉一些信息,而让编译器去尝试在编译期自动推导出来。\n", 9 | "\n", 10 | "Scala编译器可以推导下面两种情况:\n", 11 | "- 缺少参数的方法调用或构造器调用\n", 12 | "- 缺少了从一个类型到另一个类型的转换,这也适用于需要转换才能进行的对象方法调用\n", 13 | "\n", 14 | "使用隐式转换能够减少代码,能够向已有类型中注入新的方法,也能够创建领域特定语言(DSL)。" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## 1 隐式参数\n", 22 | "### 1.1 隐式参数的例子" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 1, 28 | "metadata": { 29 | "collapsed": false 30 | }, 31 | "outputs": [ 32 | { 33 | "data": { 34 | "text/plain": [ 35 | "defined \u001b[32mfunction \u001b[36mcalcTax\u001b[0m\n", 36 | "defined \u001b[32mobject \u001b[36mSimpleStateSalesTax\u001b[0m\n", 37 | "defined \u001b[32mclass \u001b[36mComplicatedSalesTaxData\u001b[0m\n", 38 | "defined \u001b[32mobject \u001b[36mComplicatedSalesTax\u001b[0m" 39 | ] 40 | }, 41 | "metadata": {}, 42 | "output_type": "display_data" 43 | } 44 | ], 45 | "source": [ 46 | "// 需求场景:\n", 47 | "// 提供一个计算销售税的方法\n", 48 | "// 条件:\n", 49 | "// 1. 某些应用需要知道当前事务发生的具体地点,以便增收税\n", 50 | "// 2. 为了促进购物消费,某些地方可能将年假最后几天定位“免税期”\n", 51 | "\n", 52 | "def calcTax(amount: Float)(implicit rate: Float): Float = amount*rate\n", 53 | "\n", 54 | "object SimpleStateSalesTax {\n", 55 | " implicit val rate: Float = 0.05F\n", 56 | "}\n", 57 | "\n", 58 | "case class ComplicatedSalesTaxData(\n", 59 | " baseRate: Float,\n", 60 | " isTaxHoliday: Boolean,\n", 61 | " storeId: Int\n", 62 | ")\n", 63 | "\n", 64 | "object ComplicatedSalesTax {\n", 65 | " private def extraTaxRateForStore(id: Int): Float = {\n", 66 | " // 可以通过id推断商铺地点,再计算附加税\n", 67 | " 0.0F\n", 68 | " }\n", 69 | " \n", 70 | " implicit def rate(implicit cstd: ComplicatedSalesTaxData): Float =\n", 71 | " if (cstd.isTaxHoliday) 0.0F\n", 72 | " else cstd.baseRate + extraTaxRateForStore(cstd.storeId)\n", 73 | "}" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 2, 79 | "metadata": { 80 | "collapsed": false 81 | }, 82 | "outputs": [ 83 | { 84 | "name": "stdout", 85 | "output_type": "stream", 86 | "text": [ 87 | "Tax on 100.0 = 5.0\n" 88 | ] 89 | }, 90 | { 91 | "data": { 92 | "text/plain": [ 93 | "\u001b[32mimport \u001b[36mSimpleStateSalesTax.rate\u001b[0m\n", 94 | "\u001b[36mamount\u001b[0m: \u001b[32mFloat\u001b[0m = \u001b[32m100.0\u001b[0mF" 95 | ] 96 | }, 97 | "metadata": {}, 98 | "output_type": "display_data" 99 | } 100 | ], 101 | "source": [ 102 | "{\n", 103 | " import SimpleStateSalesTax.rate\n", 104 | " \n", 105 | " val amount = 100F\n", 106 | " println(s\"Tax on $amount = ${calcTax(amount)}\")\n", 107 | "}" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 3, 113 | "metadata": { 114 | "collapsed": false 115 | }, 116 | "outputs": [ 117 | { 118 | "name": "stdout", 119 | "output_type": "stream", 120 | "text": [ 121 | "Tax on 100.0 = 6.0\n" 122 | ] 123 | }, 124 | { 125 | "data": { 126 | "text/plain": [ 127 | "\u001b[32mimport \u001b[36mComplicatedSalesTax.rate\u001b[0m\n", 128 | "\u001b[36mmyStore\u001b[0m: \u001b[32mComplicatedSalesTaxData\u001b[0m = \u001b[33mComplicatedSalesTaxData\u001b[0m(\u001b[32m0.06\u001b[0mF, false, \u001b[32m1010\u001b[0m)\n", 129 | "\u001b[36mamount\u001b[0m: \u001b[32mFloat\u001b[0m = \u001b[32m100.0\u001b[0mF" 130 | ] 131 | }, 132 | "metadata": {}, 133 | "output_type": "display_data" 134 | } 135 | ], 136 | "source": [ 137 | "{\n", 138 | " import ComplicatedSalesTax.rate\n", 139 | " implicit val myStore = ComplicatedSalesTaxData(0.06F, false, 1010)\n", 140 | " \n", 141 | " val amount = 100F\n", 142 | " println(s\"Tax on $amount = ${calcTax(amount)}\")\n", 143 | "}" 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": { 149 | "collapsed": true 150 | }, 151 | "source": [ 152 | "### 1.2 implicitly方法\n", 153 | "使用Predef对象定义的implicitly方法与附加类别签名结合,可以使用一种便捷的方式定义一个**接受参数化类型隐式参数的函数**。" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 4, 159 | "metadata": { 160 | "collapsed": false 161 | }, 162 | "outputs": [ 163 | { 164 | "data": { 165 | "text/plain": [ 166 | "\u001b[32mimport \u001b[36mmath.Ordering\u001b[0m\n", 167 | "defined \u001b[32mclass \u001b[36mMyList\u001b[0m" 168 | ] 169 | }, 170 | "metadata": {}, 171 | "output_type": "display_data" 172 | } 173 | ], 174 | "source": [ 175 | "import math.Ordering\n", 176 | "\n", 177 | "case class MyList[A](list: List[A]) {\n", 178 | " def sortBy1[B](f: A => B)(implicit ord: Ordering[B]): List[A] = \n", 179 | " list.sortBy(f)(ord)\n", 180 | " \n", 181 | " def sortBy2[B: Ordering](f: A => B): List[A] =\n", 182 | " list.sortBy(f)(implicitly[Ordering[B]])\n", 183 | "}" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 5, 189 | "metadata": { 190 | "collapsed": false 191 | }, 192 | "outputs": [ 193 | { 194 | "data": { 195 | "text/plain": [ 196 | "\u001b[36mlist\u001b[0m: \u001b[32mMyList\u001b[0m[\u001b[32mInt\u001b[0m] = \u001b[33mMyList\u001b[0m(\u001b[33mList\u001b[0m(\u001b[32m1\u001b[0m, \u001b[32m3\u001b[0m, \u001b[32m5\u001b[0m, \u001b[32m2\u001b[0m, \u001b[32m4\u001b[0m))" 197 | ] 198 | }, 199 | "metadata": {}, 200 | "output_type": "display_data" 201 | } 202 | ], 203 | "source": [ 204 | "val list = MyList(List(1, 3, 5, 2, 4))" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": 6, 210 | "metadata": { 211 | "collapsed": false 212 | }, 213 | "outputs": [ 214 | { 215 | "data": { 216 | "text/plain": [ 217 | "\u001b[36mres5\u001b[0m: \u001b[32mList\u001b[0m[\u001b[32mInt\u001b[0m] = \u001b[33mList\u001b[0m(\u001b[32m5\u001b[0m, \u001b[32m4\u001b[0m, \u001b[32m3\u001b[0m, \u001b[32m2\u001b[0m, \u001b[32m1\u001b[0m)" 218 | ] 219 | }, 220 | "metadata": {}, 221 | "output_type": "display_data" 222 | } 223 | ], 224 | "source": [ 225 | "list sortBy1 (i => -i)" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 7, 231 | "metadata": { 232 | "collapsed": false 233 | }, 234 | "outputs": [ 235 | { 236 | "data": { 237 | "text/plain": [ 238 | "\u001b[36mres6\u001b[0m: \u001b[32mList\u001b[0m[\u001b[32mInt\u001b[0m] = \u001b[33mList\u001b[0m(\u001b[32m5\u001b[0m, \u001b[32m4\u001b[0m, \u001b[32m3\u001b[0m, \u001b[32m2\u001b[0m, \u001b[32m1\u001b[0m)" 239 | ] 240 | }, 241 | "metadata": {}, 242 | "output_type": "display_data" 243 | } 244 | ], 245 | "source": [ 246 | "list sortBy2 (i => -i)" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "MyList类提供了两种sorBy方法:\n", 254 | "- 第一种使用常规方法,该方法接受一个类型为Ordering[B]的隐式值作为输入,**在当前作用域中一定存在某个Ordering[B]的对象实例,该实例清楚地知道对B类型对象如何进行排序。**所以,这个例子中,上下文限定了B对实例排序的能力。\n", 255 | "- 第二种方法提供了简化版的语法,类型参数`B: Ordering`被上下文定界(context bound),它安置隐式参数列表将接受Ordering[B]实例。\n", 256 | "\n", 257 | "implicitly方法会对传给函数的所有标记为隐式参数的实例进行解析。" 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "metadata": { 263 | "collapsed": true 264 | }, 265 | "source": [ 266 | "### 1.3 绕开类型擦除带来的限制" 267 | ] 268 | }, 269 | { 270 | "cell_type": "markdown", 271 | "metadata": { 272 | "collapsed": false 273 | }, 274 | "source": [ 275 | "``` scala\n", 276 | "object M {\n", 277 | " def m(seq: Seq[Int]): Unit = println(s\"Seq[Int]: $seq\")\n", 278 | " \n", 279 | " def m(seq: Seq[String]): Unit = println(s\"Seq[String]: $seq\")\n", 280 | "}\n", 281 | "```" 282 | ] 283 | }, 284 | { 285 | "cell_type": "markdown", 286 | "metadata": {}, 287 | "source": [ 288 | "将会出现这样的报错:\n", 289 | "```\n", 290 | "Compilation Failed\n", 291 | "Main.scala:50: double definition:\n", 292 | "def m(seq: Seq[Int]): Unit at line 49 and\n", 293 | "def m(seq: Seq[String]): Unit at line 50\n", 294 | "have same type after erasure: (seq: Seq)Unit\n", 295 | " def m(seq: Seq[String]): Unit = println(s\"Seq[String]: $seq\")\n", 296 | " ^\n", 297 | "```" 298 | ] 299 | }, 300 | { 301 | "cell_type": "markdown", 302 | "metadata": {}, 303 | "source": [ 304 | "因为上面的两个m方法的字节码是一样的,编译器不允许同时出现这些方法定义。\n", 305 | "\n", 306 | "不过我们可以添加隐式参数来消除这些方法的二义性。" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": 8, 312 | "metadata": { 313 | "collapsed": false 314 | }, 315 | "outputs": [ 316 | { 317 | "data": { 318 | "text/plain": [ 319 | "defined \u001b[32mobject \u001b[36mM\u001b[0m" 320 | ] 321 | }, 322 | "metadata": {}, 323 | "output_type": "display_data" 324 | } 325 | ], 326 | "source": [ 327 | "object M {\n", 328 | " implicit object IntMarker\n", 329 | " implicit object StringMarker\n", 330 | " \n", 331 | " def m(seq: Seq[Int])(implicit i: IntMarker.type): Unit = println(s\"Seq[Int]: $seq\")\n", 332 | " def m(seq: Seq[String])(implicit s: StringMarker.type): Unit = println(s\"Seq[String]: $seq\")\n", 333 | "}" 334 | ] 335 | }, 336 | { 337 | "cell_type": "code", 338 | "execution_count": 9, 339 | "metadata": { 340 | "collapsed": false 341 | }, 342 | "outputs": [ 343 | { 344 | "data": { 345 | "text/plain": [ 346 | "\u001b[32mimport \u001b[36mM._\u001b[0m" 347 | ] 348 | }, 349 | "metadata": {}, 350 | "output_type": "display_data" 351 | } 352 | ], 353 | "source": [ 354 | "import M._" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": 10, 360 | "metadata": { 361 | "collapsed": false 362 | }, 363 | "outputs": [ 364 | { 365 | "name": "stdout", 366 | "output_type": "stream", 367 | "text": [ 368 | "Seq[Int]: List(1, 2, 3)\r\n" 369 | ] 370 | }, 371 | { 372 | "data": { 373 | "text/plain": [] 374 | }, 375 | "metadata": {}, 376 | "output_type": "display_data" 377 | } 378 | ], 379 | "source": [ 380 | "m(List(1, 2, 3))" 381 | ] 382 | }, 383 | { 384 | "cell_type": "code", 385 | "execution_count": 11, 386 | "metadata": { 387 | "collapsed": false 388 | }, 389 | "outputs": [ 390 | { 391 | "name": "stdout", 392 | "output_type": "stream", 393 | "text": [ 394 | "Seq[String]: List(one, two, three)\n" 395 | ] 396 | }, 397 | { 398 | "data": { 399 | "text/plain": [] 400 | }, 401 | "metadata": {}, 402 | "output_type": "display_data" 403 | } 404 | ], 405 | "source": [ 406 | "m(List(\"one\", \"two\", \"three\"))" 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": 12, 412 | "metadata": { 413 | "collapsed": false 414 | }, 415 | "outputs": [ 416 | { 417 | "data": { 418 | "text/plain": [ 419 | "\u001b[36mres11\u001b[0m: \u001b[32mIntMarker\u001b[0m.type = cmd7$$user$M$IntMarker$@39546a" 420 | ] 421 | }, 422 | "metadata": {}, 423 | "output_type": "display_data" 424 | } 425 | ], 426 | "source": [ 427 | "IntMarker" 428 | ] 429 | }, 430 | { 431 | "cell_type": "code", 432 | "execution_count": 13, 433 | "metadata": { 434 | "collapsed": false 435 | }, 436 | "outputs": [ 437 | { 438 | "data": { 439 | "text/plain": [ 440 | "\u001b[36mres12\u001b[0m: \u001b[32mStringMarker\u001b[0m.type = cmd7$$user$M$StringMarker$@a1f49b" 441 | ] 442 | }, 443 | "metadata": {}, 444 | "output_type": "display_data" 445 | } 446 | ], 447 | "source": [ 448 | "StringMarker" 449 | ] 450 | }, 451 | { 452 | "cell_type": "markdown", 453 | "metadata": {}, 454 | "source": [ 455 | "为了尽量避免使用Int和String这样常用类型作为隐式参数和对应值(这些类型还可能出现多处定义,而导致二义性和编译器抛出错误),比较安全的做法是专门设计特有的类型作为隐式参数。" 456 | ] 457 | }, 458 | { 459 | "cell_type": "markdown", 460 | "metadata": {}, 461 | "source": [ 462 | "### 1.4 @implicitNotFound注解\n", 463 | "@implicitNotFound注解告诉编译器在不能构造出带有该注解的类型的参数时给出错误提示。这样做事给程序员有意义的错误提示。\n", 464 | "\n", 465 | "比如CanBuildFrom构造器和<:<类有相关注解:\n", 466 | "\n", 467 | "``` scala\n", 468 | "@implicitNotFound(msg = \"Cannot construct a collection of type ${To} with elements of type ${Elem} based on a collection of type ${From}.\")\n", 469 | "trait CanBuildFrom[-From, -Elem, +To] {...}\n", 470 | "```" 471 | ] 472 | }, 473 | { 474 | "cell_type": "markdown", 475 | "metadata": { 476 | "collapsed": true 477 | }, 478 | "source": [ 479 | "``` scala\n", 480 | "@implicitNotFound(msg = \"Cannot prove that ${From} <:< ${To}.\")\n", 481 | "sealed abstract class <:<[-From, +To] extends (From => To) with Serializable\n", 482 | "\n", 483 | "```" 484 | ] 485 | }, 486 | { 487 | "cell_type": "markdown", 488 | "metadata": { 489 | "collapsed": true 490 | }, 491 | "source": [ 492 | "## 2 隐式参数的规则\n", 493 | "- 只有最后一个参数列表允许出现隐式参数\n", 494 | "- implicit关键字必须出现在参数列表的最左边,而且只能出现一次\n", 495 | "- 假如参数列表以implicit关键字开头,那么所有的参数都是隐式的" 496 | ] 497 | } 498 | ], 499 | "metadata": { 500 | "kernelspec": { 501 | "display_name": "Scala 2.11", 502 | "language": "scala211", 503 | "name": "scala211" 504 | }, 505 | "language_info": { 506 | "codemirror_mode": "text/x-scala", 507 | "file_extension": ".scala", 508 | "mimetype": "text/x-scala", 509 | "name": "scala211", 510 | "pygments_lexer": "scala", 511 | "version": "2.11.6" 512 | } 513 | }, 514 | "nbformat": 4, 515 | "nbformat_minor": 0 516 | } 517 | -------------------------------------------------------------------------------- /type_system/type_bound.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 1. 类型边界\n", 8 | "类型边界是与类型相关的规则,一个变量要匹配一个类型时必须符合这些规则。\n", 9 | "\n", 10 | "类型边界的两种形式:\n", 11 | "- 类型上界(超类型约束,也称为一致性关系)\n", 12 | "- 类型下界(子类型约束)\n", 13 | "\n", 14 | "类型上界是指,某一类型必须是另一种类型的子类型。类型下界表示某类型必须是另一个类型的父类(或该类型本身)。\n", 15 | "\n", 16 | "**类型边界与型变标记是两个不相干的问题。类型边界对参数化类型所允许采用的类型做了限制,如T <: AnyRef。型变标记表示参数化类型的子类实例是否可以替换父类实例。**" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "collapsed": true 23 | }, 24 | "source": [ 25 | "实际场景中,常常使用型变标记和类型边界配合的工作方式,这主要是为了解决在错误的位置使用型变参数的问题,下面以Option的getOrElse方法作为例子进行解释:\n", 26 | "``` scala\n", 27 | "sealed abstract class Option[+A] extends Product with Serializable {\n", 28 | " ...\n", 29 | " @inline final def getOrElse[B >: A](default: => B): B = {...}\n", 30 | " ...\n", 31 | "}\n", 32 | "```\n", 33 | "可以看到,为何getOrElse方法返回B(A的父类型)呢?这里解释原因。" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 1, 39 | "metadata": { 40 | "collapsed": false 41 | }, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "text/plain": [ 46 | "defined \u001b[32mclass \u001b[36mParent\u001b[0m\n", 47 | "defined \u001b[32mclass \u001b[36mChild\u001b[0m" 48 | ] 49 | }, 50 | "metadata": {}, 51 | "output_type": "display_data" 52 | } 53 | ], 54 | "source": [ 55 | "class Parent(val value: Int) { \n", 56 | " override def toString = s\"${this.getClass.getName}($value)\"\n", 57 | "}\n", 58 | "\n", 59 | "class Child(value: Int) extends Parent(value)" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 2, 65 | "metadata": { 66 | "collapsed": false 67 | }, 68 | "outputs": [ 69 | { 70 | "data": { 71 | "text/plain": [ 72 | "\u001b[36mop1\u001b[0m: \u001b[32mOption\u001b[0m[\u001b[32mParent\u001b[0m] = Some(cmd0$$user$Child(1))\n", 73 | "\u001b[36mp1\u001b[0m: \u001b[32mParent\u001b[0m = cmd0$$user$Child(1)" 74 | ] 75 | }, 76 | "metadata": {}, 77 | "output_type": "display_data" 78 | } 79 | ], 80 | "source": [ 81 | "val op1: Option[Parent] = Option(new Child(1))\n", 82 | "val p1: Parent = op1.getOrElse(new Parent(10))" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 3, 88 | "metadata": { 89 | "collapsed": false 90 | }, 91 | "outputs": [ 92 | { 93 | "data": { 94 | "text/plain": [ 95 | "\u001b[36mop2\u001b[0m: \u001b[32mOption\u001b[0m[\u001b[32mParent\u001b[0m] = None\n", 96 | "\u001b[36mp2a\u001b[0m: \u001b[32mParent\u001b[0m = cmd0$$user$Parent(10)\n", 97 | "\u001b[36mp2b\u001b[0m: \u001b[32mParent\u001b[0m = cmd0$$user$Child(100)" 98 | ] 99 | }, 100 | "metadata": {}, 101 | "output_type": "display_data" 102 | } 103 | ], 104 | "source": [ 105 | "val op2: Option[Parent] = Option[Parent](null) // None\n", 106 | "val p2a: Parent = op2.getOrElse(new Parent(10)) // Result: Parent(10)\n", 107 | "val p2b: Parent = op2.getOrElse(new Child(100)) // Result: Child(100)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 4, 113 | "metadata": { 114 | "collapsed": false 115 | }, 116 | "outputs": [ 117 | { 118 | "data": { 119 | "text/plain": [ 120 | "\u001b[36mop3\u001b[0m: \u001b[32mOption\u001b[0m[\u001b[32mParent\u001b[0m] = None\n", 121 | "\u001b[36mp3a\u001b[0m: \u001b[32mParent\u001b[0m = cmd0$$user$Parent(20)\n", 122 | "\u001b[36mp3b\u001b[0m: \u001b[32mParent\u001b[0m = cmd0$$user$Child(200)" 123 | ] 124 | }, 125 | "metadata": {}, 126 | "output_type": "display_data" 127 | } 128 | ], 129 | "source": [ 130 | "val op3: Option[Parent] = Option[Child](null) // None\n", 131 | "val p3a: Parent = op3.getOrElse(new Parent(20)) // Result: Parent(20)\n", 132 | "val p3b: Parent = op3.getOrElse(new Child(200)) // Result: Child(200)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "关键在这里:\n", 140 | "``` scala\n", 141 | "val op3: Option[Parent] = Option[Child](null)\n", 142 | "val p3a: Parent = op3.getOrElse(new Parent(20))\n", 143 | "```\n", 144 | "op3显式地将`Option[Child](null)`(即None)赋给了`Option[Parent]`。\n", 145 | "\n", 146 | "但从调用者的角度,我们并不知道真实类型到底是什么?如果调用者持有对`Option[Parent]`的引用,那么将自然认为它可以从Option[Parent]中提取一个Parent值。故如果是None的话,调用者将返回默认的Parent参数;如果是Some[Parent],则返回Some中的值。**所有情况都认为返回一个Parent类型的值。但实际返回的是Child子类的实例。**如果不适用类型下界说明,那么`val p3a: Parent = op3.getOrElse(new Parent(20))`语句将无法通过类型检查。\n", 147 | "\n", 148 | "这就是编译器不允许简单的方法签名,而采用[B >: A]边界标记的签名的原因。" 149 | ] 150 | }, 151 | { 152 | "cell_type": "markdown", 153 | "metadata": {}, 154 | "source": [ 155 | "**同时使用类型上下界的例子**" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 5, 161 | "metadata": { 162 | "collapsed": false 163 | }, 164 | "outputs": [ 165 | { 166 | "data": { 167 | "text/plain": [ 168 | "defined \u001b[32mclass \u001b[36mUpper\u001b[0m\n", 169 | "defined \u001b[32mclass \u001b[36mMiddle1\u001b[0m\n", 170 | "defined \u001b[32mclass \u001b[36mMiddle2\u001b[0m\n", 171 | "defined \u001b[32mclass \u001b[36mLower\u001b[0m\n", 172 | "defined \u001b[32mclass \u001b[36mC\u001b[0m" 173 | ] 174 | }, 175 | "metadata": {}, 176 | "output_type": "display_data" 177 | } 178 | ], 179 | "source": [ 180 | "class Upper\n", 181 | "class Middle1 extends Upper\n", 182 | "class Middle2 extends Middle1\n", 183 | "class Lower extends Middle2\n", 184 | "case class C[A >: Lower <: Upper](a: A)\n", 185 | "// case class C2[A <: Upper >: Lower](a: A) // Does not compile" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "## 2. 通过引入新的类型参数来解决协变和逆变故障\n", 193 | "这里的实例中,我们实现一个List中简化的++版本,将两个集合类型组合起来。\n", 194 | "\n", 195 | "我们希望能有自动转换功能,比如把字符串列表转换为Any列表,所以把参数类型标注为协变。" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 6, 201 | "metadata": { 202 | "collapsed": false 203 | }, 204 | "outputs": [ 205 | { 206 | "ename": "", 207 | "evalue": "", 208 | "output_type": "error", 209 | "traceback": [ 210 | "Compilation Failed", 211 | "\u001b[31mMain.scala:78: covariant type ItemType occurs in contravariant position in type $user.this.List[ItemType] of value other\r", 212 | " def ++(other: List[ItemType]): List[ItemType]\r", 213 | " ^\u001b[0m" 214 | ] 215 | } 216 | ], 217 | "source": [ 218 | "// ++方法定义为接受另一个ItemType类型的里诶包作为参数\n", 219 | "// 返回新列表\n", 220 | "trait List[+ItemType] {\n", 221 | " def ++(other: List[ItemType]): List[ItemType]\n", 222 | "}" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "上面由于ItemType出现在了逆变位置上,出现了编译报错。\n", 230 | "\n", 231 | "为了绕开编译器限制,我们可以用新类型参数来避免把ItemType放在逆变位置上。" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": 7, 237 | "metadata": { 238 | "collapsed": false 239 | }, 240 | "outputs": [ 241 | { 242 | "data": { 243 | "text/plain": [ 244 | "defined \u001b[32mtrait \u001b[36mList\u001b[0m" 245 | ] 246 | }, 247 | "metadata": {}, 248 | "output_type": "display_data" 249 | } 250 | ], 251 | "source": [ 252 | "// 简单绕开型变约束\n", 253 | "trait List[+ItemType] {\n", 254 | " def ++[OtherItemType](other: List[OtherItemType]): List[ItemType]\n", 255 | "}" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 8, 261 | "metadata": { 262 | "collapsed": false 263 | }, 264 | "outputs": [ 265 | { 266 | "ename": "", 267 | "evalue": "", 268 | "output_type": "error", 269 | "traceback": [ 270 | "Compilation Failed", 271 | "\u001b[31mMain.scala:81: type mismatch;", 272 | " found : cmd6.this.$ref$cmd5.List[OtherItemType]", 273 | " required: cmd6.this.$ref$cmd5.List[ItemType]\r", 274 | " def ++[OtherItemType](other: List[OtherItemType]) = other\r", 275 | " ^\u001b[0m" 276 | ] 277 | } 278 | ], 279 | "source": [ 280 | "// 实现空List类\n", 281 | "class EmptyList[ItemType] extends List[ItemType] {\n", 282 | " def ++[OtherItemType](other: List[OtherItemType]) = other\n", 283 | "}" 284 | ] 285 | }, 286 | { 287 | "cell_type": "markdown", 288 | "metadata": {}, 289 | "source": [ 290 | "由于上面定义的方法得到的结果类型不匹配,OtherItemType和ItemType类型不兼容,造成编译失败。\n", 291 | "\n", 292 | "可以通过对OtherItemType做某种类型约束,使得OtherItemType和ItemType类型建立联系。\n", 293 | "\n", 294 | "我们希望OtherItemType是能和当前列表很好的组合的类型,因为ItemType是协变的,那么可以把当前列表向ItemType层级上方转换。**因此,我们用ItemType作为OtherItemType的下界约束,我们修正++方法,返回OtherItemType类型。**" 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": 9, 300 | "metadata": { 301 | "collapsed": false 302 | }, 303 | "outputs": [ 304 | { 305 | "data": { 306 | "text/plain": [ 307 | "defined \u001b[32mtrait \u001b[36mList\u001b[0m" 308 | ] 309 | }, 310 | "metadata": {}, 311 | "output_type": "display_data" 312 | } 313 | ], 314 | "source": [ 315 | "trait List[+ItemType] {\n", 316 | " def ++[OtherItemType >: ItemType](\n", 317 | " other: List[OtherItemType]): List[OtherItemType]\n", 318 | "}" 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "execution_count": 10, 324 | "metadata": { 325 | "collapsed": false 326 | }, 327 | "outputs": [ 328 | { 329 | "data": { 330 | "text/plain": [ 331 | "defined \u001b[32mclass \u001b[36mEmptyList\u001b[0m" 332 | ] 333 | }, 334 | "metadata": {}, 335 | "output_type": "display_data" 336 | } 337 | ], 338 | "source": [ 339 | "class EmptyList[ItemType] extends List[ItemType] {\n", 340 | " def ++[OtherItemType >: ItemType](\n", 341 | " other: List[OtherItemType]) = other\n", 342 | "}" 343 | ] 344 | }, 345 | { 346 | "cell_type": "markdown", 347 | "metadata": {}, 348 | "source": [ 349 | "// 确认把各类型的空list组合是否返回我们期望的类型" 350 | ] 351 | }, 352 | { 353 | "cell_type": "code", 354 | "execution_count": 11, 355 | "metadata": { 356 | "collapsed": false 357 | }, 358 | "outputs": [ 359 | { 360 | "data": { 361 | "text/plain": [ 362 | "\u001b[36mstrings\u001b[0m: \u001b[32mEmptyList\u001b[0m[\u001b[32mString\u001b[0m] = cmd7$$user$EmptyList@fb8491" 363 | ] 364 | }, 365 | "metadata": {}, 366 | "output_type": "display_data" 367 | } 368 | ], 369 | "source": [ 370 | "val strings = new EmptyList[String]" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": 12, 376 | "metadata": { 377 | "collapsed": false 378 | }, 379 | "outputs": [ 380 | { 381 | "data": { 382 | "text/plain": [ 383 | "\u001b[36mints\u001b[0m: \u001b[32mEmptyList\u001b[0m[\u001b[32mInt\u001b[0m] = cmd7$$user$EmptyList@1cc1a6" 384 | ] 385 | }, 386 | "metadata": {}, 387 | "output_type": "display_data" 388 | } 389 | ], 390 | "source": [ 391 | "val ints = new EmptyList[Int]" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": 13, 397 | "metadata": { 398 | "collapsed": false 399 | }, 400 | "outputs": [ 401 | { 402 | "data": { 403 | "text/plain": [ 404 | "\u001b[36manys\u001b[0m: \u001b[32mEmptyList\u001b[0m[\u001b[32mAny\u001b[0m] = cmd7$$user$EmptyList@1b7cf4" 405 | ] 406 | }, 407 | "metadata": {}, 408 | "output_type": "display_data" 409 | } 410 | ], 411 | "source": [ 412 | "val anys = new EmptyList[Any]" 413 | ] 414 | }, 415 | { 416 | "cell_type": "code", 417 | "execution_count": 14, 418 | "metadata": { 419 | "collapsed": false 420 | }, 421 | "outputs": [ 422 | { 423 | "data": { 424 | "text/plain": [ 425 | "\u001b[36mres11\u001b[0m: \u001b[32mList\u001b[0m[\u001b[32mString\u001b[0m] = cmd7$$user$EmptyList@fb8491" 426 | ] 427 | }, 428 | "metadata": {}, 429 | "output_type": "display_data" 430 | } 431 | ], 432 | "source": [ 433 | "strings ++ strings" 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": 15, 439 | "metadata": { 440 | "collapsed": false 441 | }, 442 | "outputs": [ 443 | { 444 | "data": { 445 | "text/plain": [ 446 | "\u001b[36mres12\u001b[0m: \u001b[32mList\u001b[0m[\u001b[32mAny\u001b[0m] = cmd7$$user$EmptyList@1cc1a6" 447 | ] 448 | }, 449 | "metadata": {}, 450 | "output_type": "display_data" 451 | } 452 | ], 453 | "source": [ 454 | "strings ++ ints" 455 | ] 456 | }, 457 | { 458 | "cell_type": "code", 459 | "execution_count": 16, 460 | "metadata": { 461 | "collapsed": false 462 | }, 463 | "outputs": [ 464 | { 465 | "data": { 466 | "text/plain": [ 467 | "\u001b[36mres13\u001b[0m: \u001b[32mList\u001b[0m[\u001b[32mAny\u001b[0m] = cmd7$$user$EmptyList@1b7cf4" 468 | ] 469 | }, 470 | "metadata": {}, 471 | "output_type": "display_data" 472 | } 473 | ], 474 | "source": [ 475 | "strings ++ anys" 476 | ] 477 | }, 478 | { 479 | "cell_type": "markdown", 480 | "metadata": {}, 481 | "source": [ 482 | "可以看到,编译器推断出Any是String和Int的共同超类,于是得到了Any列表,这正是我们期望的结果。\n", 483 | "\n", 484 | "**一般来说,当在类方法里碰到协变和逆变故障时,通常的解决办法是引入一个新的类型参数,在方法签名里用新引入的类型参数。**\n", 485 | "\n", 486 | "所以,当我们向一个不可变集合添加新元素以构成一个新的集合时(包括上面这个例子),**其类型参数必须具有逆变的行为,但传入的是协变的参数化类型。**\n", 487 | "\n", 488 | "**总的来说,那些类型参数为协变的参数化类型,与方法参数的类型下界关系密切。**" 489 | ] 490 | } 491 | ], 492 | "metadata": { 493 | "kernelspec": { 494 | "display_name": "Scala 2.11", 495 | "language": "scala211", 496 | "name": "scala211" 497 | }, 498 | "language_info": { 499 | "codemirror_mode": "text/x-scala", 500 | "file_extension": ".scala", 501 | "mimetype": "text/x-scala", 502 | "name": "scala211", 503 | "pygments_lexer": "scala", 504 | "version": "2.11.6" 505 | } 506 | }, 507 | "nbformat": 4, 508 | "nbformat_minor": 0 509 | } 510 | -------------------------------------------------------------------------------- /basics/basics1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 偏函数\n", 8 | "- 偏函数是它们并不处理所有可能的输入,而只处理那些能与至少一个case语句匹配的输入。\n", 9 | "- 在偏函数中只能使用case语句,而整个函数必须用花括号包围。如果偏函数被调用,而函数的输入却与所有语句都不匹配,系统就会抛出一个MatchError运行时错误。\n", 10 | "- 偏函数可以使用链式连接:`pf1 orElse pf2 orElse pf3 ...`。" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": { 17 | "collapsed": false 18 | }, 19 | "outputs": [ 20 | { 21 | "data": { 22 | "text/plain": [ 23 | "\u001b[36mpf1\u001b[0m: \u001b[32mPartialFunction\u001b[0m[\u001b[32mAny\u001b[0m, \u001b[32mString\u001b[0m] = \n", 24 | "\u001b[36mpf2\u001b[0m: \u001b[32mPartialFunction\u001b[0m[\u001b[32mAny\u001b[0m, \u001b[32mString\u001b[0m] = \n", 25 | "\u001b[36mpf\u001b[0m: \u001b[32mPartialFunction\u001b[0m[\u001b[32mAny\u001b[0m, \u001b[32mString\u001b[0m] = \n", 26 | "defined \u001b[32mfunction \u001b[36mtryPF\u001b[0m\n", 27 | "defined \u001b[32mfunction \u001b[36md\u001b[0m" 28 | ] 29 | }, 30 | "metadata": {}, 31 | "output_type": "display_data" 32 | } 33 | ], 34 | "source": [ 35 | "val pf1: PartialFunction[Any, String] = { case s: String => \"YES\" }\n", 36 | "val pf2: PartialFunction[Any, String] = { case d: Double => \"YES\" }\n", 37 | "val pf = pf1 orElse pf2\n", 38 | "\n", 39 | "def tryPF(x: Any, f: PartialFunction[Any, String]): String = {\n", 40 | " try {\n", 41 | " f(x).toString\n", 42 | " }\n", 43 | " catch {\n", 44 | " case _: MatchError => \"ERROR!\"\n", 45 | " }\n", 46 | "}\n", 47 | "\n", 48 | "def d(x: Any, f: PartialFunction[Any, String]) = \n", 49 | " f.isDefinedAt(x).toString" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 2, 55 | "metadata": { 56 | "collapsed": false 57 | }, 58 | "outputs": [ 59 | { 60 | "name": "stdout", 61 | "output_type": "stream", 62 | "text": [ 63 | " | pf1 - String | pf2 - Double | pf - All" 64 | ] 65 | }, 66 | { 67 | "data": { 68 | "text/plain": [] 69 | }, 70 | "metadata": {}, 71 | "output_type": "display_data" 72 | }, 73 | { 74 | "name": "stdout", 75 | "output_type": "stream", 76 | "text": [ 77 | "\r\n", 78 | " x | def? | pf1(x) | def? | pf2(x) | def? | pf(x)\r\n", 79 | "++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n", 80 | "str | true | YES | false | ERROR! | true | YES \n", 81 | "3.14 | false | ERROR! | true | YES | true | YES \n", 82 | "10 | false | ERROR! | false | ERROR! | false | ERROR!\n" 83 | ] 84 | } 85 | ], 86 | "source": [ 87 | "println(\" | pf1 - String | pf2 - Double | pf - All\")\n", 88 | "println(\" x | def? | pf1(x) | def? | pf2(x) | def? | pf(x)\")\n", 89 | "println(\"++++++++++++++++++++++++++++++++++++++++++++++++++++++\")\n", 90 | "List(\"str\", 3.14, 10) foreach { x =>\n", 91 | " printf(\"%-5s | %-5s | %-6s | %-5s | %-6s | %-5s | %-6s\\n\", x.toString,\n", 92 | " d(x, pf1), tryPF(x, pf1), d(x, pf2), tryPF(x, pf2), d(x, pf), tryPF(x, pf))\n", 93 | "}" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "## Future简介\n", 101 | "scala.concurrent.Future是scala提供的并发工具,但任务封装在Future中执行时,该任务是异步的" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 3, 107 | "metadata": { 108 | "collapsed": false 109 | }, 110 | "outputs": [ 111 | { 112 | "data": { 113 | "text/plain": [ 114 | "\u001b[32mimport \u001b[36mscala.concurrent.Future\u001b[0m\n", 115 | "\u001b[32mimport \u001b[36mscala.concurrent.ExecutionContext.Implicits.global\u001b[0m" 116 | ] 117 | }, 118 | "metadata": {}, 119 | "output_type": "display_data" 120 | } 121 | ], 122 | "source": [ 123 | "import scala.concurrent.Future\n", 124 | "import scala.concurrent.ExecutionContext.Implicits.global" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 4, 130 | "metadata": { 131 | "collapsed": false 132 | }, 133 | "outputs": [ 134 | { 135 | "name": "stdout", 136 | "output_type": "stream", 137 | "text": [ 138 | "Success! returned: 2\n", 139 | "Success! returned: 3\n", 140 | "Success! returned: 1\n", 141 | "Success! returned: 4\n", 142 | "Done\n" 143 | ] 144 | }, 145 | { 146 | "data": { 147 | "text/plain": [ 148 | "defined \u001b[32mfunction \u001b[36msleep\u001b[0m\n", 149 | "defined \u001b[32mfunction \u001b[36mdoWork\u001b[0m" 150 | ] 151 | }, 152 | "metadata": {}, 153 | "output_type": "display_data" 154 | } 155 | ], 156 | "source": [ 157 | "def sleep(millis: Long) = Thread.sleep(millis)\n", 158 | "\n", 159 | "def doWork(index: Int) = {\n", 160 | " sleep((math.random * 1000).toLong)\n", 161 | " index\n", 162 | "}\n", 163 | "\n", 164 | "(1 to 5) foreach { index =>\n", 165 | " val future = Future {\n", 166 | " doWork(index)\n", 167 | " }\n", 168 | " \n", 169 | " future onSuccess {\n", 170 | " case answer: Int => println(s\"Success! returned: $answer\")\n", 171 | " }\n", 172 | " future onFailure {\n", 173 | " case th: Throwable => println(s\"FAILURE! returned: $th\")\n", 174 | " }\n", 175 | "}\n", 176 | "\n", 177 | "sleep(1000)\n", 178 | "println(\"Done\")" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "- 调用Future单例对象的工厂方法,传入一个匿名函数,表示需要做的工作\n", 186 | "- Future.apply返回新的Future对象,控制权还给循环,该对象在另一个线程中执行doWork\n", 187 | "- onSuccess注册一个回调函数,该回调函数是一个偏函数,当future成功执行完毕后,将执行该回调" 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": {}, 193 | "source": [ 194 | "### **Future API的配置隐含参数**\n", 195 | "上面代码中调用的三个方法中第二个参数列表具有隐含的ExecutionContext参数\n", 196 | "``` scala\n", 197 | "//Future.apply\n", 198 | "apply[T](body: => T)(implicit executor: ExecutionContext): Future[T]\n", 199 | "\n", 200 | "def onSuccess[U](func: (Try[T]) => U)(implicit executor: ExecutionContext): Unit\n", 201 | "def onFailure[U](callback: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit\n", 202 | "```\n", 203 | "Future通过ExecutionContext来配置并发操作的执行,默认情况使用Java的ForkJoinPool来设置管理Java线程池。" 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "metadata": {}, 209 | "source": [ 210 | "## 斐波那契数列使用的技巧" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 5, 216 | "metadata": { 217 | "collapsed": false 218 | }, 219 | "outputs": [ 220 | { 221 | "name": "stdout", 222 | "output_type": "stream", 223 | "text": [ 224 | "1\n", 225 | "1\n", 226 | "2\n", 227 | "6\n", 228 | "24\n", 229 | "120\n" 230 | ] 231 | }, 232 | { 233 | "data": { 234 | "text/plain": [ 235 | "\u001b[32mimport \u001b[36mscala.annotation.tailrec\u001b[0m\n", 236 | "defined \u001b[32mfunction \u001b[36mfactorial\u001b[0m" 237 | ] 238 | }, 239 | "metadata": {}, 240 | "output_type": "display_data" 241 | } 242 | ], 243 | "source": [ 244 | "import scala.annotation.tailrec\n", 245 | "\n", 246 | "def factorial(i: Int): Long = {\n", 247 | " @tailrec\n", 248 | " def fact(i: Int, accumulator: Int): Long = {\n", 249 | " if (i <= 1) accumulator\n", 250 | " else fact(i-1, i*accumulator)\n", 251 | " }\n", 252 | " \n", 253 | " fact(i, 1)\n", 254 | "}\n", 255 | "\n", 256 | "(0 to 5) foreach (i => println(factorial(i)))" 257 | ] 258 | }, 259 | { 260 | "cell_type": "markdown", 261 | "metadata": {}, 262 | "source": [ 263 | "- factorial使用了嵌套函数fact作为辅助函数\n", 264 | "- 由于阶乘计算结果增长快,使用Long作为返回值类型\n", 265 | "- 使用tailrec关键字让编译器检查自己是否对尾递归执行了优化,避免栈空间崩溃" 266 | ] 267 | }, 268 | { 269 | "cell_type": "code", 270 | "execution_count": 6, 271 | "metadata": { 272 | "collapsed": false 273 | }, 274 | "outputs": [ 275 | { 276 | "ename": "", 277 | "evalue": "", 278 | "output_type": "error", 279 | "traceback": [ 280 | "Compilation Failed", 281 | "\u001b[31mMain.scala:81: could not optimize @tailrec annotated method f: it is neither private nor final so can be overridden\r", 282 | "def f(i: Int): Long = {\r", 283 | " ^\u001b[0m" 284 | ] 285 | } 286 | ], 287 | "source": [ 288 | "// 不是尾递归的情况,编译器将抛出错误\n", 289 | "@tailrec\n", 290 | "def f(i: Int): Long = {\n", 291 | " if(i <= 1) 1L\n", 292 | " else f(i-2) + f(i-1)\n", 293 | "}" 294 | ] 295 | }, 296 | { 297 | "cell_type": "markdown", 298 | "metadata": {}, 299 | "source": [ 300 | "## 类型推断" 301 | ] 302 | }, 303 | { 304 | "cell_type": "markdown", 305 | "metadata": { 306 | "collapsed": true 307 | }, 308 | "source": [ 309 | "显式类型注解的场景:\n", 310 | "- 声明变量却没有初始化的情况(抽象声明)\n", 311 | "- 方法参数\n", 312 | "- 方法返回值类型:\n", 313 | " - 方法中明确使用了return\n", 314 | " - 递归方法\n", 315 | " - 多个方法重载,其中一个方法调用了另一个重载方法,调用者需要显示类型注解\n", 316 | " - Scala推断出的类型比你期望的类型更为宽泛" 317 | ] 318 | }, 319 | { 320 | "cell_type": "markdown", 321 | "metadata": {}, 322 | "source": [ 323 | "## Option、Some和None,避免使用null" 324 | ] 325 | }, 326 | { 327 | "cell_type": "markdown", 328 | "metadata": { 329 | "collapsed": true 330 | }, 331 | "source": [ 332 | "Option允许我们通过Some和None显式表示“有值”或“没有值”,通过类型检查避免空指针异常(null)的情况。" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": 7, 338 | "metadata": { 339 | "collapsed": false 340 | }, 341 | "outputs": [ 342 | { 343 | "data": { 344 | "text/plain": [ 345 | "\u001b[36mstateCapitals\u001b[0m: \u001b[32mMap\u001b[0m[\u001b[32mString\u001b[0m, \u001b[32mString\u001b[0m] = \u001b[33mMap\u001b[0m(\n", 346 | " \u001b[32m\"Alabama\"\u001b[0m -> \u001b[32m\"Montgomery\"\u001b[0m,\n", 347 | " \u001b[32m\"Alaska\"\u001b[0m -> \u001b[32m\"Juneau\"\u001b[0m,\n", 348 | " \u001b[32m\"Wyoming\"\u001b[0m -> \u001b[32m\"Cheyenne\"\u001b[0m\n", 349 | ")" 350 | ] 351 | }, 352 | "metadata": {}, 353 | "output_type": "display_data" 354 | } 355 | ], 356 | "source": [ 357 | "val stateCapitals = Map(\n", 358 | " \"Alabama\" -> \"Montgomery\",\n", 359 | " \"Alaska\" -> \"Juneau\",\n", 360 | " \"Wyoming\" -> \"Cheyenne\"\n", 361 | ")" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": 8, 367 | "metadata": { 368 | "collapsed": false 369 | }, 370 | "outputs": [ 371 | { 372 | "name": "stdout", 373 | "output_type": "stream", 374 | "text": [ 375 | "Get the capitals wrapped in Options:\n", 376 | "Alabama: Some(Montgomery)\n", 377 | "Wyoming: Some(Cheyenne)\n", 378 | "Unknown: None\n", 379 | "Get the capitals themselves out of Options:\n", 380 | "Alabama: Montgomery\n", 381 | "Wyoming: Cheyenne\n", 382 | "Unknown: Oops!\n" 383 | ] 384 | }, 385 | { 386 | "data": { 387 | "text/plain": [] 388 | }, 389 | "metadata": {}, 390 | "output_type": "display_data" 391 | } 392 | ], 393 | "source": [ 394 | "println(\"Get the capitals wrapped in Options:\")\n", 395 | "println(\"Alabama: \" + stateCapitals.get(\"Alabama\"))\n", 396 | "println(\"Wyoming: \" + stateCapitals.get(\"Wyoming\"))\n", 397 | "println(\"Unknown: \" + stateCapitals .get(\"Unknown\"))\n", 398 | "\n", 399 | "println(\"Get the capitals themselves out of Options:\")\n", 400 | "println(\"Alabama: \" + stateCapitals.get(\"Alabama\").get)\n", 401 | "println(\"Wyoming: \" + stateCapitals.get(\"Wyoming\").getOrElse(\"Oops!\"))\n", 402 | "println(\"Unknown: \" + stateCapitals .get(\"Unknown\").getOrElse(\"Oops!\"))" 403 | ] 404 | }, 405 | { 406 | "cell_type": "markdown", 407 | "metadata": {}, 408 | "source": [ 409 | "Map.get方法返回了Option[T],对于给定的key,当对应的值可能并不存在的情况,Option已经包含在方法返回的类型中了。\n", 410 | "\n", 411 | "Option有get或getOrElse方法,其中None.get会抛出一个NoSuchElementException异常。更安全的方法是使用getOrElse,其参数起到默认值的作用,避免潜在的异常。" 412 | ] 413 | }, 414 | { 415 | "cell_type": "markdown", 416 | "metadata": {}, 417 | "source": [ 418 | "## 参数化类型\n", 419 | "Scala使用方括号表示参数化类型,并通过+、-号表示协类型和逆类型。" 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": 9, 425 | "metadata": { 426 | "collapsed": false 427 | }, 428 | "outputs": [ 429 | { 430 | "data": { 431 | "text/plain": [ 432 | "\u001b[32mimport \u001b[36mjava.io._\u001b[0m\n", 433 | "defined \u001b[32mclass \u001b[36mBulkReader\u001b[0m\n", 434 | "defined \u001b[32mclass \u001b[36mStringBulkReader\u001b[0m\n", 435 | "defined \u001b[32mclass \u001b[36mFileBulkReader\u001b[0m" 436 | ] 437 | }, 438 | "metadata": {}, 439 | "output_type": "display_data" 440 | } 441 | ], 442 | "source": [ 443 | "import java.io._\n", 444 | "\n", 445 | "abstract class BulkReader[In] {\n", 446 | " val source: In\n", 447 | " def read: String\n", 448 | "}\n", 449 | "\n", 450 | "class StringBulkReader(val source: String) extends BulkReader[String] {\n", 451 | " def read: String = source\n", 452 | "}\n", 453 | "\n", 454 | "class FileBulkReader(val source: File) extends BulkReader[File] {\n", 455 | " def read: String = {\n", 456 | " val in = new BufferedInputStream(new FileInputStream(source))\n", 457 | " val numBytes = in.available()\n", 458 | " val bytes = new Array[Byte](numBytes)\n", 459 | " in.read(bytes, 0, numBytes)\n", 460 | " new String(bytes)\n", 461 | " }\n", 462 | "}" 463 | ] 464 | }, 465 | { 466 | "cell_type": "code", 467 | "execution_count": 10, 468 | "metadata": { 469 | "collapsed": false 470 | }, 471 | "outputs": [ 472 | { 473 | "name": "stdout", 474 | "output_type": "stream", 475 | "text": [ 476 | "Hello Scala!\n", 477 | "this is a file for read method of FileBulkReader class\n", 478 | "do some work\n" 479 | ] 480 | }, 481 | { 482 | "data": { 483 | "text/plain": [] 484 | }, 485 | "metadata": {}, 486 | "output_type": "display_data" 487 | } 488 | ], 489 | "source": [ 490 | "println(new StringBulkReader(\"Hello Scala!\").read)\n", 491 | "println(new FileBulkReader(new File(\"fileBulkReaderTestFile.txt\")).read)" 492 | ] 493 | } 494 | ], 495 | "metadata": { 496 | "kernelspec": { 497 | "display_name": "Scala 2.11", 498 | "language": "scala211", 499 | "name": "scala211" 500 | }, 501 | "language_info": { 502 | "codemirror_mode": "text/x-scala", 503 | "file_extension": ".scala", 504 | "mimetype": "text/x-scala", 505 | "name": "scala211", 506 | "pygments_lexer": "scala", 507 | "version": "2.11.6" 508 | } 509 | }, 510 | "nbformat": 4, 511 | "nbformat_minor": 0 512 | } 513 | --------------------------------------------------------------------------------