精华内容
下载资源
问答
  • Scala课堂

    2019-02-25 19:52:09
    Scala课堂

    分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

    分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

    展开全文
  • twitter scala课堂

    2014-04-09 16:44:30
    Scala课堂是Twitter启动的一系列讲座,用来帮助有经验的工程师成为高效的Scala 程序员。Scala是一种相对较新的语言,但借鉴了许多熟悉的概念。
  • Scala 课堂!

    2016-05-17 17:47:50
    Scala课堂是Twitter启动的一系列讲座,用来帮助有经验的工程师成为高效的Scala 程序员。Scala是一种相对较新的语言,但借鉴了许多熟悉的概念。因此,课程中的讲座假设听众知道这些概念,并展示了如何在Scala中使用...

    其他语言版本: English Русский

    关于

    Scala课堂是Twitter启动的一系列讲座,用来帮助有经验的工程师成为高效的Scala 程序员。Scala是一种相对较新的语言,但借鉴了许多熟悉的概念。因此,课程中的讲座假设听众知道这些概念,并展示了如何在Scala中使用它们。我们发现这是一个让新工程师能够快速上手的有效方法。网站里的是伴随这些讲座的书面材料,这些文字材料本身也是很有用的。

    方法

    我们认为最有意义的教学方式是,不要把Scala看做是改进的Java,而是把它作为一门新的语言。所以这里不会介绍Java的使用经验,而将聚焦在解释器和“对象-函数式”的风格,以及我们的编程风格。特别强调了可维护性,清晰的表达,和利用类型系统的优势。

    大部分课程除了Scala的交互命令行之外不需要其他软件。我们鼓励读者按顺序学习,并且不仅限于此。让这些课程作为您探索Scala的起点吧!

    另外

    通过这些链接您可以了解更多:

    课程

    基础
    值,函数,类,方法,继承,try-catch-finally。面向表达式编程
    基础知识(续)
    样本类,对象,包,应用,更新,函数即对象(统一访问原则),模式匹配。
    集合
    列表,映射,功能组合(map, foreach, filter, zip, folds)
    模式匹配与函数组合
    更多函数!偏函数,更多模式匹配
    类型和多态基础
    基本类型和类型多态性,类型推断,变性,边界,量化
    高级类型
    高级类型,视界,更高级多态性类型,递归类型,结构类型
    简单构建工具
    关于SBT——标准的Scala构建工具
    更多的集合
    Scala Collections库指南
    使用specs测试
    Scala 并发编程
    Runnable, Callable, 线程, Futures
    Java + Scala
    Java跨平台交互:在Java中使用Scala
    Finagle介绍
    Finagle原语:Future, Service, Filter, Builder
    Searchbird
    利用Finagle构建一个分布式搜索引擎
    展开全文
  • Scala课堂-6-高级类型

    2016-11-12 14:44:10
    因为Kafka是用Scala写的,为了方便学习Scala语法,此处把Twitter官方的Scala课堂转载到此处。 (原文位于http://twitter.github.io/scala_school/zh_cn/index.html,由于时常被墙,速度极慢)。视界(“View”) ...

    因为Kafka是用Scala写的,为了方便学习Scala语法,此处把Twitter官方的Scala课堂转载到此处。
    (原文位于http://twitter.github.io/scala_school/zh_cn/index.html,由于时常被墙,速度极慢)。

    视界(“View”)
    有时候,你并不需要指定一个类型是等/子/超于另一个类,你可以通过转换这个类来伪装这种关联关系。一个视界指定一个类型可以被“看作是”另一个类型。这对对象的只读操作是很有用的。 隐 函数允许类型自动转换。更确切地说,在隐式函数可以帮助满足类型推断时,它们允许按需的函数应用。例如:

    scala> implicit def strToInt(x: String) = x.toInt
    strToInt: (x: String)Int
    
    scala>  "123"
    res0: String = 123
    
    scala> val y:Int="123"
    y: Int = 123
    
    scala>  math.max("123", 111)
    res1: Int = 123

    视界,就像类型边界,要求对给定的类型存在这样一个函数。您可以使用<%指定类型限制,例如

    scala> class Container[A <% Int] { def addIt(x: A) = 123 + x }
    defined class Container

    这是说 A 必须“可被视”为 Int 。让我们试试

    scala> class Container[A <% Int] { def addIt(x: A) = 123 + x }
    defined class Container
    
    scala>  (new Container[String]).addIt("123")
    res2: Int = 246
    
    scala>  (new Container[Int]).addIt(123) 
    res3: Int = 246
    
    scala> (new Container[Float]).addIt(123.2F)
    <console>:10: error: No implicit view available from Float => Int.
                  (new Container[Float]).addIt(123.2F)

     其他类型限制
    方法可以通过隐含参数执行更复杂的类型限制。例如,List 支持对数字内容执行 sum,但对其他内容却不行。可是 Scala 的数字类型并不都共享一个超类,所以我们不能使用 T

    sum[B >: A](implicit num: Numeric[B]): B

    如果你调用 List(1,2).sum(),你并不需要传入一个 num 参数;它是隐式设置的。但如果你调用 List(“whoop”).sum(),它会抱怨无法设置 num。 在没有设定陌生的对象为 Numeric 的时候,方法可能会要求某种特定类型的“证据”。这时可以使用以下类型-关系运算符:

    |:———-|:—————–|
    |A =:= B |A 必须和 B相等 |
    |A <:< B |A 必须是 B 的子类 |
    |A <%< B |A 必须可以被看做是 B|

    scala>  class Container[A](value: A) { def addIt(implicit evidence: A =:= Int) = 123 + value }
    defined class Container
    
    scala>  (new Container(123)).addIt
    res5: Int = 246
    
    scala>  (new Container("123")).addIt
    <console>:10: error: Cannot prove that String =:= Int.
                   (new Container("123")).addIt

    使用视图进行泛型编程
    在 Scala 标准库中,视图主要用于实现集合的通用函数。例如“min”函数(在 Seq[] 上)就使用了这种技术:

    def min[B >: A](implicit cmp: Ordering[B]): A = {
      if (isEmpty)
        throw new UnsupportedOperationException("empty.min")
    
      reduceLeft((x, y) => if (cmp.lteq(x, y)) x else y)
    }

    其主要优点是:

    集合中的元素并不是必须实现 Ordered 特质,但 Ordered 的使用仍然可以执行静态类型检查。 无需任何额外的库支持,你也可以定义自己的排序:

    scala>  List(1,2,3,4).min
    res0: Int = 1
    
    scala>  List(1,2,3,4).min(new Ordering[Int] { def compare(a: Int, b: Int) = b compare a })
    res1: Int = 4

    作为旁注,标准库中有视图来将 Ordered 转换为 Ordering (反之亦然)。

    trait LowPriorityOrderingImplicits {
      implicit def ordered[A <: Ordered[A]]: Ordering[A] = new Ordering[A] {
        def compare(x: A, y: A) = x.compare(y)
      }
    }

    上下文边界和 implicitly[]
    Scala2.8引入了一种串联和访问隐式参数的快捷方式。

    scala> def foo[A](implicit x: Ordered[A]) {}
    foo: [A](implicit x: Ordered[A])Unit
    
    scala>  def foo[A : Ordered] {}        
    foo: [A](implicit evidence$1: Ordered[A])Unit

    隐式值可能会通过 implicitly 被访问

    scala>  implicitly[Ordering[Int]]
    res5: Ordering[Int] = scala.math.Ordering$Int$@4b7773c4

    更高级多态性类型 和 特设多态性
    Scala 可以对“更高阶”的类型进行抽象。例如,假设您需要用几种类型的容器处理几种类型的数据。你可能定义了一个 Container 的接口,它可以被实现为几种类型的容器:Option、List 等。你要定义可以使用这些容器里的值的接口,但不想确定值的类型。 这类似与函数柯里化。例如,尽管“一元类型”有类似 List[A] 的构造函数,这意味着我们必须满足一个“级别”的类型变量来产生一个具体的类型(就像一个没有柯里化的函数需要只提供一个参数列表来被调用),更高阶的类型需要更多。

    scala>  trait Container[M[_]] { def put[A](x: A): M[A]; def get[A](m: M[A]): A }
    defined trait Container
    
    scala>  val container = new Container[List] { def put[A](x: A) = List(x); def get[A](m: List[A]) = m.head }
    container: Container[List] = $anon$1@434013d9
    
    scala>  container.put("hey")
    res1: List[String] = List(hey)
    
    scala>  container.put(123)
    res2: List[Int] = List(123)

    注意: Container 是参数化类型的多态(“容器类型”)。 如果我们结合隐式转换 implicits 使用容器,我们会得到“特设的”多态性:即对容器写泛型函数的能力。

    scala>  trait Container[M[_]] { def put[A](x: A): M[A]; def get[A](m: M[A]): A }
    defined trait Container
    
    scala> implicit val listContainer = new Container[List] { def put[A](x: A) = List(x); def get[A](m: List[A]) = m.head }
    listContainer: Container[List] = $anon$1@54f3d86c
    
    scala> implicit val optionContainer = new Container[Some] { def put[A](x: A) = Some(x); def get[A](m: Some[A]) = m.get }
    optionContainer: Container[Some] = $anon$1@591287f8
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    def tupleize[M[_]: Container, A, B](fst: M[A], snd: M[B]) = {
          val c = implicitly[Container[M]]                             
          c.put(c.get(fst), c.get(snd))
          }
    
    // Exiting paste mode, now interpreting.
    
    tupleize: [M[_], A, B](fst: M[A], snd: M[B])(implicit evidence$1: Container[M])M[(A, B)]
    
    scala>  tupleize(Some(1), Some(2))
    res0: Some[(Int, Int)] = Some((1,2))
    
    scala>  tupleize(List(1), List(2))
    res1: List[(Int, Int)] = List((1,2))

    F-界多态性
    通常有必要来访问一个(泛型)特质的具体子类。例如,想象你有一些泛型特质,但需要可以与它的某一子类进行比较。

    trait Container extends Ordered[Container]

    然而,现在比较方法是必须的了

    def compare(that: Container): Int

    因此,我们不能访问具体子类型,例如

    class MyContainer extends Container {
      def compare(that: MyContainer): Int
    }

    编译失败,因为我们对 Container 指定了 Ordered 特质,而不是对特定子类型指定的。 为了调和这一点,我们改用 F-界的多态性。

    trait Container[A <: Container[A]] extends Ordered[A]

    奇怪的类型!但可以看到怎样对 A 实现了 Ordered 参数化,它本身就是 Container[A]

    class MyContainer extends Container[MyContainer] { 
      def compare(that: MyContainer) = 0 
    }

    他们是有序的了:

    scala>  List(new MyContainer, new MyContainer, new MyContainer)
    res0: List[MyContainer] = List(MyContainer@50e205df, MyContainer@26ef9cf5, MyContainer@3d29accb)
    
    scala>  List(new MyContainer, new MyContainer, new MyContainer).min
    res1: MyContainer = MyContainer@622e8c17

    鉴于他们都是 Container[] 的子类型,我们可以定义另一个子类并创建 Container[] 的一个混合列表:

    scala> class YourContainer extends Container[YourContainer] { def compare(that: YourContainer) = 0 }
    defined class YourContainer
    
    scala> List(new MyContainer, new MyContainer, new MyContainer, new YourContainer)               
    res2: List[Container[_ >: YourContainer with MyContainer <: Container[_ >: YourContainer with MyContainer <: Object]]] = List(MyContainer@58f59add, MyContainer@648a50cb, MyContainer@34be72fe, YourContainer@436f9cbf)

    注意结果类型是怎样成为 YourContainer 和 MyContainer 类型确定的下界。这是类型推断的工作。有趣的是,这种类型甚至不需要是有意义的,它只是提供了一个合乎逻辑的最大下界为列表的统一类型。如果现在我们尝试使用 Ordered 会发生什么?

    scala> (new MyContainer, new MyContainer, new MyContainer, new YourContainer).min
    <console>:11: error: value min is not a member of (MyContainer, MyContainer, MyContainer, YourContainer)
                  (new MyContainer, new MyContainer, new MyContainer, new YourContainer).min

    对统一的类型 Ordered[]不存在了。太糟糕了。

     结构类型
    Scala 支持 结构类型 structural types — 类型需求由接口 构造 表示,而不是由具体的类型表示。

    scala>  def foo(x: { def get: Int }) = 123 + x.get
    foo: (x: AnyRef{def get: Int})Int
    
    scala>  foo(new { def get = 10 })                 
    res4: Int = 133

     抽象类型成员
    在特质中,你可以让类型成员保持抽象。

    scala>  trait Foo { type A; val x: A; def getX: A = x }
    defined trait Foo
    
    scala> (new Foo { type A = Int; val x = 123 }).getX   
    res5: Int = 123
    
    scala>  (new Foo { type A = String; val x = "hey" }).getX
    res6: String = hey

    在做依赖注入等情况下,这往往是一个有用的技巧。

    您可以使用 hash 操作符来引用一个抽象类型的变量:

    scala> trait Foo[M[_]] { type t[A] = M[A] }
    defined trait Foo
    
    scala> val x: Foo[List]#t[Int] = List(1)
    x: List[Int] = List(1)

     类型擦除和清单
    正如我们所知道的,类型信息在编译的时候会因为 擦除 而丢失。 Scala 的 清单(Manifests) 功能,使我们能够选择性地恢复类型信息。清单提供了一个隐含值,根据需要由编译器生成。

    scala>  class MakeFoo[A](implicit manifest: Manifest[A]) { def make: A = manifest.erasure.newInstance.asInstanceOf[A] }
    defined class MakeFoo
    
    scala> (new MakeFoo[String]).make
    res7: String = ""
    展开全文
  • 因为Kafka是用Scala写的,为了方便学习Scala语法,此处把Twitter官方的Scala课堂转载到此处。 (原文位于http://twitter.github.io/scala_school/zh_cn/index.html,由于时常被墙,速度极慢)。基本数据结构 Scala...

    因为Kafka是用Scala写的,为了方便学习Scala语法,此处把Twitter官方的Scala课堂转载到此处。
    (原文位于http://twitter.github.io/scala_school/zh_cn/index.html,由于时常被墙,速度极慢)。

    基本数据结构
    Scala 提供了一些不错的集合

    列表 List

    scala>  val numbers = List(1, 2, 3, 4)
    numbers: List[Int] = List(1, 2, 3, 4)

    集 Set
    集没有重复

    scala>  Set(1, 1, 2)
    res0: scala.collection.immutable.Set[Int] = Set(1, 2)

    元组 Tuple
    元组是在不使用类的前提下,将元素组合起来形成简单的逻辑集合。

    scala> val hostPort = ("localhost", 80)
    hostPort: (String, Int) = (localhost,80)

    与样本类不同,元组不能通过名称获取字段,而是使用位置下标来读取对象;而且这个下标基于1,而不是基于0。

    scala> hostPort._1
    res1: String = localhost
    
    scala> hostPort._2
    res2: Int = 80

    元组可以很好得与模式匹配相结合。

    hostPort match {
      case ("localhost", port) => ...
      case (host, port) => ...
    }

    在创建两个元素的元组时,可以使用特殊语法:->

    scala>  1 -> 2
    res3: (Int, Int) = (1,2)

    映射 Map
    它可以持有基本数据类型。

    scala> Map(1 -> 2)
    res4: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)
    
    scala> Map("foo" -> "bar")
    res5: scala.collection.immutable.Map[String,String] = Map(foo -> bar)

    这看起来像是特殊的语法,不过不要忘了上文讨论的->可以用来创建二元组。 Map()方法也使用了从第一节课学到的变参列表:Map(1 -> “one”, 2 -> “two”)将变为 Map((1, “one”), (2, “two”)),其中第一个参数是映射的键,第二个参数是映射的值。 映射的值可以是映射甚或是函数。

    Map(1 -> Map("foo" -> "bar"))
    Map("timesTwo" -> { timesTwo(_) })

    选项 Option
    Option 是一个表示有可能包含值的容器。
    Option 基本的接口是这样的:

    trait Option[T] {
      def isDefined: Boolean
      def get: T
      def getOrElse(t: T): T
    }

    Option 本身是泛型的,并且有两个子类: Some[T] 或 None
    我们看一个使用 Option 的例子: Map.get 使用 Option 作为其返回值,表示这个方法也许不会返回你请求的值。

    scala> val numbers = Map(1 -> "one", 2 -> "two")
    numbers: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two)
    
    scala> numbers.get(2)
    res6: Option[String] = Some(two)
    
    scala> numbers.get(3)
    res7: Option[String] = None

    现在我们的数据似乎陷在 Option 中了,我们怎样获取这个数据呢? 直觉上想到的可能是在 isDefined 方法上使用条件判断来处理。

    // We want to multiply the number by two, otherwise return 0.
    val result = if (res1.isDefined) {
      res1.get * 2
    } else {
      0
    }

    我们建议使用 getOrElse 或模式匹配处理这个结果。
    getOrElse 让你轻松地定义一个默认值。

    val result = res1.getOrElse(0) * 2

    模式匹配能自然地配合 Option 使用。

    val result = res1 match {
      case Some(n) => n * 2
      case None => 0
    }

    函数组合子(Functional Combinators)
    List(1, 2, 3) map squared 对列表中的每一个元素都应用了 squared 平方函数,并返回一个新的列表 List(1, 4, 9)。我们称这个操作 map 组合子。 (如果想要更好的定义,你可能会喜欢 Stackoverflow 上对组合子的说明。)他们常被用在标准的数据结构上。

    map
    map 对列表中的每个元素应用一个函数,返回应用后的元素所组成的列表。

    scala> val numbers = List(1, 2, 3, 4)
    numbers: List[Int] = List(1, 2, 3, 4)
    
    scala>  numbers.map((i: Int) => i * 2)
    res9: List[Int] = List(2, 4, 6, 8)

    或传入一个部分应用函数

    scala> def timesTwo(i: Int): Int = i * 2
    timesTwo: (i: Int)Int
    
    scala>  numbers.map(timesTwo _)
    res10: List[Int] = List(2, 4, 6, 8)

    foreach
    foreach很像 map,但没有返回值。foreach 仅用于有副作用[side-effects]的函数。

    scala> numbers.foreach((i: Int) => i * 2)

    什么也没有返回。 你可以尝试存储返回值,但它会是 Unit 类型(即 void )

    scala> val doubled = numbers.foreach((i: Int) => i * 2)
    doubled: Unit = ()

    filter
    filter 移除任何对传入函数计算结果为 false 的元素。返回一个布尔值的函数通常被称为谓词函数[或判定函数]。

    scala>  numbers.filter((i: Int) => i % 2 == 0)
    res12: List[Int] = List(2, 4)
    
    scala> def isEven(i: Int): Boolean = i % 2 == 0
    isEven: (i: Int)Boolean
    
    scala> numbers.filter(isEven _)
    res13: List[Int] = List(2, 4)

    zip
    zip 将两个列表的内容聚合到一个对偶列表中。

    scala>  List(1, 2, 3).zip(List("a", "b", "c"))
    res14: List[(Int, String)] = List((1,a), (2,b), (3,c))

    partition
    partition 将使用给定的谓词函数分割列表。

    scala>  val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    numbers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    
    scala>  numbers.partition(_ %2 == 0)
    res15: (List[Int], List[Int]) = (List(2, 4, 6, 8, 10),List(1, 3, 5, 7, 9))

    find
    find 返回集合中第一个匹配谓词函数的元素。

    scala>  numbers.find((i: Int) => i > 5)
    res16: Option[Int] = Some(6)

    drop & dropWhile
    drop 将删除前 i 个元素

    scala>  numbers.drop(5)
    res17: List[Int] = List(6, 7, 8, 9, 10)

    dropWhile 将删除元素直到找到第一个匹配谓词函数的元素。例如,如果我们在 numbers 列表上使用 dropWhile 奇数的函数, 1将被丢弃(但3不会被丢弃,因为他被2“保护”了)。

    scala> numbers.dropWhile(_ % 2 != 0)
    res18: List[Int] = List(2, 3, 4, 5, 6, 7, 8, 9, 10)

    foldLeft

    scala> numbers.foldLeft(0)((m: Int, n: Int) => m + n)
    res19: Int = 55

    0为初始值(记住 numbers 是 List[Int] 类型),m 作为一个累加器。 直接观察运行过程:

    scala>  numbers.foldLeft(0) { (m: Int, n: Int) => println("m: " + m + " n: " + n); m + n }
    m: 0 n: 1
    m: 1 n: 2
    m: 3 n: 3
    m: 6 n: 4
    m: 10 n: 5
    m: 15 n: 6
    m: 21 n: 7
    m: 28 n: 8
    m: 36 n: 9
    m: 45 n: 10
    res20: Int = 55

    foldRight
    和 foldLeft 一样,只是运行过程相反。

    scala> numbers.foldRight(0) { (m: Int, n: Int) => println("m: " + m + " n: " + n); m + n }
    m: 10 n: 0
    m: 9 n: 10
    m: 8 n: 19
    m: 7 n: 27
    m: 6 n: 34
    m: 5 n: 40
    m: 4 n: 45
    m: 3 n: 49
    m: 2 n: 52
    m: 1 n: 54
    res21: Int = 55

    flatten
    flatten 将嵌套结构扁平化为一个层次的集合。

    scala> List(List(1, 2), List(3, 4)).flatten
    res22: List[Int] = List(1, 2, 3, 4)

    flatMap
    flatMap 是一种常用的组合子,结合映射[mapping]和扁平化[flattening]。 flatMap 需要一个处理嵌套列表的函数,然后将结果串连起来。

    scala>  val nestedNumbers = List(List(1, 2), List(3, 4))
    nestedNumbers: List[List[Int]] = List(List(1, 2), List(3, 4))
    
    scala> nestedNumbers.flatMap(x => x.map(_ * 2))
    res23: List[Int] = List(2, 4, 6, 8)

    可以把它看做是“先映射后扁平化”的快捷操作:

    scala>  nestedNumbers.map((x: List[Int]) => x.map(_ * 2)).flatten
    res24: List[Int] = List(2, 4, 6, 8)

    扩展函数组合子
    现在我们已经学过集合上的一些函数。 我们将尝试写自己的函数组合子。 有趣的是,上面所展示的每一个函数组合子都可以用 fold 方法实现。让我们看一些例子。

    scala> def ourMap(numbers: List[Int], fn: Int => Int): List[Int] = {
         |   numbers.foldRight(List[Int]()) { (x: Int, xs: List[Int]) =>
         |     fn(x) :: xs
         |   }
         | }
    ourMap: (numbers: List[Int], fn: Int => Int)List[Int]
    
    scala>  ourMap(numbers, timesTwo(_))
    res25: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

    为什么是 ListInt?Scala 没有聪明到理解你的目的是将结果积聚在一个空的 Int 类型的列表中。

    Map?
    所有展示的函数组合子都可以在 Map 上使用。Map 可以被看作是一个二元组的列表,所以你写的函数要处理一个键和值的二元组。

    scala>  val extensions = Map("steve" -> 100, "bob" -> 101, "joe" -> 201)
    extensions: scala.collection.immutable.Map[String,Int] = Map(steve -> 100, bob -> 101, joe -> 201)

    现在筛选出电话分机号码低于200的条目。

    scala>  extensions.filter((namePhone: (String, Int)) => namePhone._2 < 200)
    res26: scala.collection.immutable.Map[String,Int] = Map(steve -> 100, bob -> 101)

    因为参数是元组,所以你必须使用位置获取器来读取它们的键和值。呃! 幸运的是,我们其实可以使用模式匹配更优雅地提取键和值。

    scala>  extensions.filter({case (name, extension) => extension < 200})
    res27: scala.collection.immutable.Map[String,Int] = Map(steve -> 100, bob -> 101)
    展开全文
  • 因为Kafka是用Scala写的,为了方便学习Scala语法,此处把Twitter官方的Scala课堂转载到此处。 (原文位于http://twitter.github.io/scala_school/zh_cn/index.html,由于时常被墙,速度极慢)。
  • 因为Kafka是用Scala写的,为了方便学习Scala语法,此处把Twitter官方的Scala课堂转载到此处。 (原文位于http://twitter.github.io/scala_school/zh_cn/index.html,由于时常被墙,速度极慢)。apply 方法 当类或...
  • 让我们创建两个函数:scala> def f(s: String) = "f(" + s + ")" f: (s: String)Stringscala> def g(s: String) = "g(" + s + ")" g: (s: String)Stringcompose compose 组合其他函数形成一个新的函数 f(g(x))scala...
  • Scala课堂-5-类型和多态类型

    千次阅读 2016-11-12 14:37:27
    粗略地说,这意味着在 Scala 中,有一些你想表达的类型概念“过于泛化”以至于编译器无法理解。假设你有一个函数 def toList[ A ]( a: A ) = List(a) 你希望继续泛型地使用它: def foo[ A, B ]( f: A ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,405
精华内容 562
关键字:

scala课堂