diff --git a/_zh-cn/tour/basics.md b/_zh-cn/tour/basics.md new file mode 100644 index 0000000000..9d9e46abc1 --- /dev/null +++ b/_zh-cn/tour/basics.md @@ -0,0 +1,323 @@ +--- +layout: tour +title: 基础 + +discourse: false + +partof: scala-tour + +num: 2 +language: zh-cn +next-page: unified-types +previous-page: tour-of-scala + +redirect_from: "/tutorials/tour/basics.html" +--- + +这篇文章涵盖了Scala的基础知识。 + +## 在浏览器上尝试Scala + +你可以在浏览器上使用ScalaFiddle运行Scala。 + +1. 打开[https://scalafiddle.io](https://scalafiddle.io); +2. 在左侧窗格中粘贴`println("Hello, world!")`; +3. 点击"Run"按钮,输出将展现在右侧窗格中。 + +这是一种简单的、零设置的方法来实践Scala的代码片段。 + +这篇文档中的大部分代码示例集成了ScalaFiddle,直接点击“Run"按钮即可运行。 + +## 表达式 + +表达式是可计算的语句。 +``` +1 + 1 +``` +你可以使用`println`来输出表达式的结果。 + +{% scalafiddle %} +```tut +println(1) // 1 +println(1 + 1) // 2 +println("Hello!") // Hello! +println("Hello," + " world!") // Hello, world! +``` +{% endscalafiddle %} + +### 常量(`Values`) + +你可以使用`val`关键字来给表达式的结果命名。 + +```tut +val x = 1 + 1 +println(x) // 2 +``` + +对于结果比如这里的`x`的命名,被称为常量(`values`)。引用一个常量(`value`)不会再次计算。 + +常量(`values`)不能重新被赋值。 + +```tut:nofail +val x = 1 + 1 +x = 3 // This does not compile. +``` + +常量(`values`)的类型可以被推断,或者你也可以显示地声明类型,例如: + +```tut +val x: Int = 1 + 1 +``` + +注意下,在标识符`x`的后面、类型声明`Int`的前面,还需要一个冒号`:`。 + +### 变量 + +除了可以重新赋值,变量和常量类似。你可以使用`var`关键字来定义一个变量。 + +```tut +var x = 1 + 1 +x = 3 // This compiles because "x" is declared with the "var" keyword. +println(x * x) // 9 +``` + +和常量一样,你可以显示地声明类型: + +```tut +var x: Int = 1 + 1 +``` + + +## 代码块(Blocks) + +你可以组合几个表达式,并且用`{}`包围起来。我们称之为代码块(block)。 + +代码块中最后一个表达式的结果,也正是整个块的结果。 + +```tut +println({ + val x = 1 + 1 + x + 1 +}) // 3 +``` + +## 函数 + +函数是带有参数的表达式。 + +你可以定义一个匿名函数(即没有名字),来返回一个给定整数加一的结果。 + +```tut +(x: Int) => x + 1 +``` + +`=>`的左边是参数列表,右边是一个包含参数的表达式。 + +你也可以给函数命名。 + +{% scalafiddle %} +```tut +val addOne = (x: Int) => x + 1 +println(addOne(1)) // 2 +``` +{% endscalafiddle %} + +函数可带有多个参数。 + +{% scalafiddle %} +```tut +val add = (x: Int, y: Int) => x + y +println(add(1, 2)) // 3 +``` +{% endscalafiddle %} + +或者不带参数。 + +```tut +val getTheAnswer = () => 42 +println(getTheAnswer()) // 42 +``` + +## 方法 + +方法的表现和行为和函数非常类似,但是它们之间有一些关键的差别。 + +方法由`def`关键字定义。`def`后面跟着一个名字、参数列表、返回类型和方法体。 + +{% scalafiddle %} +```tut +def add(x: Int, y: Int): Int = x + y +println(add(1, 2)) // 3 +``` +{% endscalafiddle %} + +注意返回类型是怎么在函数列表和一个冒号`: Int`之后声明的。 + +方法可以接受多个参数列表。 + +{% scalafiddle %} +```tut +def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier +println(addThenMultiply(1, 2)(3)) // 9 +``` +{% endscalafiddle %} + +或者没有参数列表。 + +```tut +def name: String = System.getProperty("user.name") +println("Hello, " + name + "!") +``` + +还有一些其他的区别,但是现在你可以认为方法就是类似于函数的东西。 + +方法也可以有多行的表达式。 +```tut +def getSquareString(input: Double): String = { + val square = input * input + square.toString +} +``` +方法体的最后一个表达式就是方法的返回值。(Scala中也有一个`return`关键字,但是很少使用) + +## 类 + +你可以使用`class`关键字定义一个类,后面跟着它的名字和构造参数。 + +```tut +class Greeter(prefix: String, suffix: String) { + def greet(name: String): Unit = + println(prefix + name + suffix) +} +``` +`greet`方法的返回类型是`Unit`,表明没有什么有意义的需要返回。它有点像Java和C语言中的`void`。(不同点在于每个Scala表达式都必须有值,事实上有个`Unit`类型的单例值,写作`()`,它不携带任何信息) + +你可以使用`new`关键字创建一个类的实例。 + +```tut +val greeter = new Greeter("Hello, ", "!") +greeter.greet("Scala developer") // Hello, Scala developer! +``` + +我们将在[后面](classes.html)深入介绍类。 + +## 样例类 + +Scala有一种特殊的类叫做样例类(case class)。默认情况下,样例类一般用于不可变对象,并且可作值比较。你可以使用`case class`关键字来定义样例类。 + +```tut +case class Point(x: Int, y: Int) +``` + +你可以不用`new`关键字来实例化样例类。 + +```tut +val point = Point(1, 2) +val anotherPoint = Point(1, 2) +val yetAnotherPoint = Point(2, 2) +``` + +并且它们的值可以进行比较。 + +```tut +if (point == anotherPoint) { + println(point + " and " + anotherPoint + " are the same.") +} else { + println(point + " and " + anotherPoint + " are different.") +} +// Point(1,2) and Point(1,2) are the same. + +if (point == yetAnotherPoint) { + println(point + " and " + yetAnotherPoint + " are the same.") +} else { + println(point + " and " + yetAnotherPoint + " are different.") +} +// Point(1,2) and Point(2,2) are different. +``` + +关于样例类,还有不少内容我们乐于介绍,并且我们确信你会爱上它们。我们会在[后面](case-classes.html)深入介绍它们。 + +## 对象 + +对象是它们自己定义的单实例,你可以把它看作它自己的类的单例。 + +你可以使用`object`关键字定义对象。 + +```tut +object IdFactory { + private var counter = 0 + def create(): Int = { + counter += 1 + counter + } +} +``` + +你可以通过引用它的名字来访问一个对象。 + +```tut +val newId: Int = IdFactory.create() +println(newId) // 1 +val newerId: Int = IdFactory.create() +println(newerId) // 2 +``` + +我们会在[后面](singleton-objects.html)深入介绍它们。 + +## 特质 + +特质是包含某些字段和方法的类型。可以组合多个特质。 + +你可以使用`trait`关键字定义特质。 + +```tut +trait Greeter { + def greet(name: String): Unit +} +``` + +特质也可以有默认的实现。 + +{% scalafiddle %} +```tut +trait Greeter { + def greet(name: String): Unit = + println("Hello, " + name + "!") +} +``` + +你可以使用`extends`关键字来继承特质,使用`override`关键字来覆盖默认的实现。 + +```tut +class DefaultGreeter extends Greeter + +class CustomizableGreeter(prefix: String, postfix: String) extends Greeter { + override def greet(name: String): Unit = { + println(prefix + name + postfix) + } +} + +val greeter = new DefaultGreeter() +greeter.greet("Scala developer") // Hello, Scala developer! + +val customGreeter = new CustomizableGreeter("How are you, ", "?") +customGreeter.greet("Scala developer") // How are you, Scala developer? +``` +{% endscalafiddle %} + +这里,`DefaultGreeter`仅仅继承了一个特质,它还可以继承多个特质。 + +我们会在[后面](traits.html)深入介绍特质。 + +## 主方法 + +主方法是一个程序的入口点。JVM要求一个名为`main`的主方法,接受一个字符串数组的参数。 + +通过使用对象,你可以如下所示来定义一个主方法。 + +```tut +object Main { + def main(args: Array[String]): Unit = + println("Hello, Scala developer!") +} +``` diff --git a/_zh-cn/tour/classes.md b/_zh-cn/tour/classes.md new file mode 100644 index 0000000000..7439128bcb --- /dev/null +++ b/_zh-cn/tour/classes.md @@ -0,0 +1,110 @@ +--- +layout: tour +title: 类 + +discourse: true + +partof: scala-tour + +language: zh-cn +num: 4 +next-page: traits +previous-page: unified-types +topics: classes +prerequisite-knowledge: no-return-keyword, type-declaration-syntax, string-interpolation, procedures + +redirect_from: "/tutorials/tour/classes.html" +--- + +Scala中的类是用于创建对象的蓝图,其中包含了方法、常量、变量、类型、对象、特质、类,这些统称为成员。类型、对象和特质将在后面的文章中介绍。 + +## 类定义 +一个最简的类的定义就是关键字`class`+标识符,类名必须是大写。 +```tut +class User + +val user1 = new User +``` +关键字`new`被用于创建类的实例。`User`由于没有定义任何构造器,因而只有一个不带任何参数的默认构造器。然而,你通常需要一个构造器和类体。下面是类定义的一个例子: + +```tut +class Point(var x: Int, var y: Int) { + + def move(dx: Int, dy: Int): Unit = { + x = x + dx + y = y + dy + } + + override def toString: String = + s"($x, $y)" +} + +val point1 = new Point(2, 3) +point1.x // 2 +println(point1) // prints (2, 3) +``` + +`Point`类有4个成员:变量`x`和`y`,方法`move`和`toString`。与许多其他语言不同,主构造方法在类的签名中`(var x: Int, var y: Int)`。`move`方法带有2个参数,返回无任何意义的`Unit`类型值`()`。这一点与Java这类语言中的`void`相当。另外,`toString`方法不带任何参数但是返回一个`String`值。因为`toString`覆盖了[`AnyRef`](unified-types.html)中的`toString`方法,所以用了`override`关键字标记。 + +## 构造器 + +构造器可以通过提供一个默认值来拥有可选参数: + +```tut +class Point(var x: Int = 0, var y: Int = 0) + +val origin = new Point // x and y are both set to 0 +val point1 = new Point(1) +println(point1.x) // prints 1 + +``` + +在这个版本的`Point`类中,`x`和`y`拥有默认值`0`所以没有必传参数。然而,因为构造器是从左往右读取参数,所以如果仅仅要传个`y`的值,你需要带名传参。 +``` +class Point(var x: Int = 0, var y: Int = 0) +val point2 = new Point(y=2) +println(point2.y) // prints 2 +``` + +这样的做法在实践中有利于使得表达明确无误。 + +## 私有成员和Getter/Setter语法 +成员默认是公有(`public`)的。使用`private`访问修饰符可以在函数外部隐藏它们。 +```tut +class Point { + private var _x = 0 + private var _y = 0 + private val bound = 100 + + def x = _x + def x_= (newValue: Int): Unit = { + if (newValue < bound) _x = newValue else printWarning + } + + def y = _y + def y_= (newValue: Int): Unit = { + if (newValue < bound) _y = newValue else printWarning + } + + private def printWarning = println("WARNING: Out of bounds") +} + +val point1 = new Point +point1.x = 99 +point1.y = 101 // prints the warning +``` +在这个版本的`Point`类中,数据存在私有变量`_x`和`_y`中。`def x`和`def y`方法用于访问私有数据。`def x_=`和`def y_=`是为了验证和给`_x`和`_y`赋值。注意下对于setter方法的特殊语法:这个方法在getter方法的后面加上`_=`,后面跟着参数。 + +主构造方法中带有`val`和`var`的参数时公有的。然而由于`val`是不可变的,所以不能像下面这样去使用。 +``` +class Point(val x: Int, val y: Int) +val point = new Point(1, 2) +point.x = 3 // <-- does not compile +``` + +不带`val`或`var`的参数是私有的,仅在类中可见。 +``` +class Point(x: Int, y: Int) +val point = new Point(1, 2) +point.x // <-- does not compile +``` diff --git a/_zh-cn/tour/tour-of-scala.md b/_zh-cn/tour/tour-of-scala.md index 84952d4480..7f08aad362 100644 --- a/_zh-cn/tour/tour-of-scala.md +++ b/_zh-cn/tour/tour-of-scala.md @@ -53,9 +53,9 @@ Scala配备了一个拥有强大表达能力的类型系统,它可以静态地 * [隐式类](http://docs.scala-lang.org/overviews/core/implicit-classes.html)允许给已有的类型添加扩展方法。 * [字符串插值](/overviews/core/string-interpolation.html)可以让用户使用自定义的插值器进行扩展。 -## Scala的交互 +## Scala的互操作性 -通过使用流行的Java运行环境(JRE),Scala设计了很好的交互。特别是与主流的面向对象的Java编程语言的交互尽可能的平滑。Java的最新特性如函数接口(SAMs)、[lambda表达式](higher-order-functions.html)、[注解](annotations.html)及[泛型类](generic-classes.html) 在Scala中都有类似的实现。 +Scala设计的目标是与流行的Java运行环境(JRE)进行良好的互操作,特别是与主流的面向对象编程语言——Java的互操作尽可能的平滑。Java的最新特性如函数接口(SAMs)、[lambda表达式](higher-order-functions.html)、[注解](annotations.html)及[泛型类](generic-classes.html) 在Scala中都有类似的实现。 另外有些Java中并没有的特性,如[缺省参数值](default-parameter-values.html)和[带名字的参数](named-arguments.html)等,也是尽可能地向Java靠拢。Scala拥有类似Java的编译模型(独立编译、动态类加载),且允许使用已有的成千上万的高质量类库。 diff --git a/_zh-cn/tour/unified-types.md b/_zh-cn/tour/unified-types.md new file mode 100644 index 0000000000..52e6091fb5 --- /dev/null +++ b/_zh-cn/tour/unified-types.md @@ -0,0 +1,84 @@ +--- +layout: tour +title: 统一类型 + +discourse: true + +partof: scala-tour + +num: 3 +language: zh-cn +next-page: classes +previous-page: basics +prerequisite-knowledge: classes, basics + +redirect_from: "/tutorials/tour/unified-types.html" +--- + +在Scala中,所有的值都有类型,包括数值和函数。下图阐述了类型层次结构的一个子集。 + +Scala Type Hierarchy + +## Scala类型层次结构 ## + +[`Any`](http://www.scala-lang.org/api/2.12.1/scala/Any.html)是所有类型的超类型,也称为顶级类 +型。它定义了一些通用的方法如`equals`、`hashCode`和`toString`。`Any`有两个直接子类:`AnyVal`和`AnyRef`。 + +`AnyVal`代表值类型。有9个预定义的非空的值类型分别是:`Double`、`Float`、`Long`、`Int`、`Short`、`Byte`、`Char`、`Unit`和`Boolean`。`Unit`是不带任何意义的值类型,它仅有一个实例可以像这样声明:`()`。所有的函数必须有返回,所以说有时候`Unit`也是有用的返回类型。 + +`AnyRef`代表引用类型。所有非值类型都被定义为引用类型。在Scala中,每个用户自定义的类型都是`AnyRef`的子类型。如果Scala被应用在Java的运行环境中,`AnyRef`相当于`java.lang.Object`。 + +这里有一个例子,说明了字符串、整型、布尔值和函数都是对象,这一点和其他对象一样: + +```tut +val list: List[Any] = List( + "a string", + 732, // an integer + 'c', // a character + true, // a boolean value + () => "an anonymous function returning a string" +) + +list.foreach(element => println(element)) +``` + +这里定义了一个类型`List`的变量`list`。这个列表里由多种类型进行初始化,但是它们都是`scala.Any`的实例,所以可以把它们加入到列表中。 + +下面是程序的输出: + +``` +a string +732 +c +true + +``` + +## 类型转换 +值类型可以按照下面的方向进行转换: +Scala Type Hierarchy + +例如: + +```tut +val x: Long = 987654321 +val y: Float = x // 9.8765434E8 (note that some precision is lost in this case) + +val face: Char = '☺' +val number: Int = face // 9786 +``` + +转换是单向,下面这样写将不会通过编译。 + +``` +val x: Long = 987654321 +val y: Float = x // 9.8765434E8 +val z: Long = y // Does not conform +``` + +你可以将一个类型转换为子类型,这点将在后面的文章介绍。 + +## Nothing和Null +`Nothing`是所有类型的子类型,也称为底部类型。没有一个值是`Nothing`类型的。它的用途之一是给出非正常终止的信号,如抛出异常、程序退出或者一个无限循环(可以理解为它是一个不对值进行定义的表达式的类型,或者是一个不能正常返回的方法)。 + +`Null`是所有引用类型的子类型(即`AnyRef`的任意子类型)。它有一个单例值由关键字`null`所定义。`Null`主要是使得Scala满足和其他JVM语言的互操作性,但是几乎不应该在Scala代码中使用。我们将在后面的章节中介绍`null`的替代方案。