为 Scala 的 OSS 生态系统做出贡献

添加新指南/教程

语言

为什么要贡献新的学习资料?

正如 Heather Miller 所写,为 docs.scala-lang.org 做出贡献对于让 Scala 对新手、经验丰富的程序员和任何好奇的人来说都是至关重要的。对于任何习惯使用 Scala 但可能不想使用编译器等复杂工具的人来说,这也是一种做出贡献的绝佳方式。

架构

此文档网站由一个开源的 GitHub 存储库 支持,并且始终可以贡献。

内容

目前,此存储库中支持的文档类型

  • 指南/概述/书籍:特定语言功能的权威指南/概述。通常是篇幅较长、内容详尽的文档,通常由 Scala 团队成员编写。一个示例是 集合 概述。
  • 参考:由 Scala 团队成员编写的语言功能规范参考。这些内容提供了确切的规范,以便理解语言的更微妙方面。一个示例是 Scala 3 参考
  • 教程:篇幅短小、示例丰富且简洁的文章,旨在让开发人员快速上手。
  • 备忘单:Scala 语法和行为的快速参考。

实施

该网站是使用 Markdown 源代码通过 Jekyll 静态生成的,并托管在 GitHub Pages 上。选择此工作流是为了帮助贡献者专注于编写有用的内容,而不是配置和样板。它还有助于在中心位置发布静态站点。

正在使用的 Markdown 语法支持 Maruku 扩展,并具有自动语法高亮功能,无需任何标记。

此外,mdoc 在拉取请求期间用于验证 Scala 代码块。要使用此功能,您必须使用 mdoc 记录的重音符符号,请参阅此处 了解示例。

注意:仅由 mdoc 完成代码验证,并且不会生成额外的输出。

提交文档

要提交新文档,您应首先 分叉 存储库,然后使用 Markdown 编写您的文章(如下面的示例),最后提交拉取请求。在经过一些编辑和讨论后,您的文档将 docs.scala-lang.org 上线。

---
layout: singlepage-overview
title: My Awesome Title
---

## An h2 Header in Markdown

And a paragraph, with a [link](https://scala-lang.org.cn).

目录将自动生成在您的文档的侧边栏中,并提供语法高亮。

文档被接受的标准

此文档存储库的目标是经过精心策划,而不是像 wiki 等其他社区驱动的文档平台的方法。因此,要包含在 docs.scala-lang.org 中,文档必须

  • “适合”该存储库(,它不应是另一篇文章的完全副本),
  • 经过完善,即它必须全面、完整、正确且有条理;作为一篇文章编写,以便许多用户理解。
  • 维护,如果文档可能需要不时进行修订,请做好随时更新的准备,或指定某人负责。

如果您有想要贡献的内容,或正在考虑撰写内容以进行贡献,我们很乐意考虑!请随时在 GitHub 问题和请求拉取以及 #scala-contributors 房间 Discord 中提出任何问题、疑虑、澄清等。

代码块

各种文档通常需要代码示例。您可以通过以下方式在 Markdown 文档中贡献代码

  • 内联,在代码周围加上反引号,
  • 用三个反引号包围,
  • 或缩进 4 个空格,例如
inline example: `val x = 23`

block example:

```scala
println("hello")
```

indented example:

    case class Foo(x: Int)

Scala 2 与 Scala 3

我们的目标是拥有一个统一的文档,涵盖 Scala 2 和 Scala 3。在许多情况下,Scala 2 和 Scala 3 中的代码示例是相同的,但有时会有一些语法差异。在一些不太常见的情况下,页面可能会解释 Scala 3 中的新概念,而在 Scala 2 中没有等效概念,或者解释 Scala 3 中已删除的概念。在所有情况下,文档都应清楚地“标记”代码示例,以便读者知道它们在哪些版本的 Scala 中有效。

以下部分解释了如何正确“标记”代码示例。

标记 Scala 2 和 Scala 3 中都可用的概念的页面中的代码片段

当页面的内容不特定于 Scala 2 或 Scala 3 时,例如我们的 Hello World Scala Book 章节,代码片段应显示 Scala 2 和 Scala 3 语法。我们通过根据以下规则在选项卡中标记代码片段来实现此目的

  • 如果 Scala 2 和 Scala 3 中的惯用语法不同,我们会创建两个选项卡,“Scala 2”和“Scala 3”,显示相应的语法
  • 如果代码片段在 Scala 2 和 Scala 3 中都是惯用的,我们会创建一个选项卡,“Scala 2 和 3”
  • 如果代码片段仅在 Scala 2 或 Scala 3 中有效,我们会创建一个选项卡,“仅限 Scala 2”或“仅限 Scala 3”

以下是如何使用 tabs 指令和类 tabs-scala-version 在 Markdown 中生成此类选项卡的示例

{% tabs hello-world-demo class=tabs-scala-version %}

{% tab 'Scala 2' %}
```scala
object hello extends App {
  println("Hello, World!")
}
```
{% endtab %}

{% tab 'Scala 3' %}
```scala
@main def hello() = println("Hello, World!")
```
{% endtab %}

{% endtabs %}

至关重要的是,您使用 tabs-scala-version 类,以受益于一些很酷的用户交互

  • 同一页面上的所有其他 Scala 版本选项卡也会切换到当前选项卡,只要其中一个发生更改。
  • 选中的选项卡将在整个网站中记住,并且当用户在一段时间后返回该页面时,该选项卡也将被记住。

对于在 Scala 2 和 Scala 3 中都有效的代码片段,请使用一个标记为 'Scala 2 and 3' 的选项卡(请注意,tabs-scala-version 类也被删除了)。

{% tabs scala-2-and-3-demo %}
{% tab 'Scala 2 and 3' %}
```scala
List(1, 2, 3).map(x => x + 1).sum
```
{% endtab %}
{% endtabs %}

对于仅适用于 Scala 2 或 Scala 3 中的一个的示例,请使用选项卡 'Scala 2 Only''Scala 3 Only'

如果您有一个特别长的选项卡,为了可读性,您可以使用参数 for=tab-group 指出它所属的选项卡组,如下例所示

{% tabs my-tab-group class=tabs-scala-version %}
...
{% tab 'Scala 3' for=my-tab-group %}
...

标记一个记录特定于 Scala 版本的概念的完整页面

当页面内容解释了一个在 Scala 3 中是新的且在 Scala 2 中没有等效项的概念(例如 TASTy),或在 Scala 3 中已被删除的概念时,我们标记整个页面,而不是标记每个代码示例。

我们通过在 Markdown 文件的 YAML 前置内容 中设置几个属性来实现这一点。例如,对于特定于 Scala 3 的页面

scala3: true
versionSpecific: true

或者,对于特定于 Scala 2 的页面

scala2: true
versionSpecific: true

请注意,当整个页面被标记时,其代码示例不需要有选项卡。

类型检查示例

网站构建过程使用 mdoc 对 markdown 中的代码片段进行类型检查。这是一个确保您包含的代码片段进行类型检查并且有效的好方法。以下是一些快速入门提示

首先,在创建代码块时,在 scala 之后添加 mdoc。这里的 mdoc 修饰符将确保 mdoc 运行代码片段并确保其有效。

            ```scala mdoc
val a = 1
```

如果您有一个您希望失败的片段,您还可以使用 mdoc:fail 来解决编译错误,mdoc:crash 来解决运行时错误。

```scala mdoc:fail
val b: String = 3 // won't compile
```

请记住,单个文件全部编译为一个单元,因此你无法重新定义在其他代码片段中上面定义的变量。然而,有几种方法可以解决这个问题。首先,你可以使用 mdoc:nest 修饰符,它将用 scala.Predef.locally{...} 包装代码片段。这实际上会将代码片段“隐藏”起来。解决此问题的另一种方法是使用 mdoc:reset 修饰符,它会重置并忘记上面的一切。下面是使用各种修饰符的一个示例。

```scala mdoc
import java.time.Instant

def now() = Instant.now()
object Foo {}
```
```scala mdoc:nest
case class Foo(a: Int) // conflicts with Foo above, but it's nested so it's fine
```
```scala mdoc
val a = s"The time is ${now()}" // still have access to the now method from above
```
```scala mdoc:reset
case class Foo(a: String) // forget the previous Foo's and start fresh
```
```scala mdoc
val myFoo = Foo("hi") // now we only have access to the last Foo
```

文档模板

指南/概述

可以逻辑地放在一个 Markdown 页面上的指南或概述应放在目录 _overviews/RELEVANT-CATEGORY/ 中。它应具有标题

---
layout: singlepage-overview
title: YOUR TITLE
---

文档的其余部分将以 Markdown 语法编写。

你可以用任何相关的目录替换 RELEVANT-CATEGORY,或者如果找不到合适的目录,则创建一个新的目录。

如果你的指南/概述包含多个页面,例如 集合 概述,则必须指定顺序,方法是在标题中使用 num 标记按逻辑顺序对文档编号,并使用 partof 标记为页面集合分配一个名称。例如,以下标题可用于集合概述中的文档

---
layout: multipage-overview
title: YOUR TITLE

partof: collections
num: 10
---

集合中的至少一个文档必须在标题中包含一个标记 outof,该标记指示大型概述中的文档总数。通常最好将它放在概述的最后一页上

---
layout: multipage-overview
title: YOUR TITLE

partof: collections
num: 15
outof: 15
---

索引页面(例如 docs.scala-lang.org/overviews/index.html)是通过读取配置文件(例如 _data/overviews.yml)中的数据生成的,因此你的概述应放在那里的一个类别中。

教程

教程不同于指南,它们应该以更简洁、面向任务的风格编写,通常在一页上。

与指南类似,教程也使用相同的 Markdown 标题。

编写完教程后,为了帮助用户导航,必须将他们的链接添加到 /tutorials.md 的元数据中。例如,它可能如下所示

---
layout: root-index-layout
title: Tutorials

tutorials:
...
- title: My New Tutorial
  url: "/tutorials/my-new-tutorial.html"
  description: "Learn How To Do This Specific Task"
  icon: code
---

还必须将教程添加到导航栏中的下拉列表中。为此,请向 _data/doc-nav-header.yml 中添加一个额外的条目。即

---
- title: Getting Started
  url: "/getting-started/index.html"
- title: Learn
  ...
- title: Tutorials
  url: "#"
  submenu:
  ...
  - title: My New Tutorial
    url: "/tutorials/my-new-tutorial.html"
...
---

备忘单

备忘单具有特殊的布局,并且内容应为 Markdown 表格。要提供备忘单,应使用以下格式

---
layout: cheatsheet
title: YOUR TITLE
by: YOUR NAME
about: SOME TEXT ABOUT THE CHEAT SHEET.
---
| Title A | Title B |
|---------|---------|
| content | more    |

本页面的贡献者