六、Kotlin 文件中的注释

计算机语言文件中的注释是不属于计算机语言本身的文本,因此对程序执行没有影响,但提供了程序中使用的元素和结构的文本描述。注释有助于读者理解你的程序。

从技术角度来看,注释很容易生成,并与程序语法本身相区别。

  • 以双斜线//(不在字符串中)开始到行尾的所有内容都是注释。

  • 所有以/*开始并以*/结束的内容(都不在字符串中)都是注释,不管它跨越了多少行。

乍一看,注释似乎是程序中一个不错的特性,添加或省略注释似乎是每个开发人员的个人决定。不过,评论还有更多的内容。仔细看看这件事,评论是在两个界限之间的范围内处理的:

  • 完全不写注释:对于短程序和那些结构非常好、不言自明的程序来说,完全不写注释是一种有效的、尽管有争议的立场。这种方法的优点是显而易见的:您必须编写更少的代码,没有混淆注释和源代码的危险,并且正确地遵循这种方法将会产生高质量的综合代码。但是也有缺点:您可能错误地评估了您的代码是否是自解释的,依赖于注释的工具不提供输出,或者您公司的质量保证指南可能被违反。

  • 冗长的注释 : 另一方面,如果你冗长地注释你程序的每一个部分,你将不得不写很多,并且你可能会忽略代码质量,因为程序中模糊或混乱的结构被注释澄清了。

最佳方法介于这些限制之间。作为一个经验法则,你应该为类、接口和单例对象写注释,解释它们的好处,并且你应该在它们中注释公共函数,包括它们的参数描述。

注意

我欠你一个坦白。前几章的NumberGuess游戏应用在我提供的来源中没有包含任何评论。为了保持列表较小,注释被省略了,这些列表周围的浮动文本充当了读者的替代品。在你读完这一章之后,你可以随意修改这个问题,并给那里的类、接口和单例对象添加适当的注释。

在这一章中,我们将介绍如何将注释添加到 Kotlin 文件中,包括如何使用它们。

包注释

我们了解到包与文件相对应,它们的目的和功能有很强的凝聚力。从技术角度来看,每个包也对应于操作系统文件层次结构中的一个目录。

通过适当的注释来描述包是有意义的,我们在 Kotlin 中这样做的方式如下:对于每个包,也就是说在每个文件夹中,创建一个文件package-info.md。要在 Android Studio 中实现这一点,你必须在项目浏览器中切换到项目文件视图类型(参见图 6-1 )。单击 Android 旁边的灰色向下小矩形来切换视图类型。然后,您可以右键单击其中一个包,并从快捷菜单中选择“新建➤文件”。输入完整的文件名package-info.md

后缀为.md的文件是降价文件。Markdown 是一种类似于 HTML 的样式语言,但是有自己简化的语法。我们将很快描述 Markdown,但首先我们必须教会 Android Studio 如何处理 Markdown 文件。为此,双击其中一个新的package-info.md文件。工作室在其标准文本编辑器中打开该文件,但它在编辑窗格的顶部显示一条警告消息,如图 6-2 所示。

img/476388_1_En_6_Fig2_HTML.jpg

图 6-2。

Android Studio 试图打开一个降价文件

img/476388_1_En_6_Fig1_HTML.jpg

图 6-1。

项目文件视图

单击安装插件链接。在随后的屏幕上,接受任何许可声明,如果询问,选择使用 JetBrains 的 markdown 支持。

在每个package-info.md文件中,让第一行读作

# Package full.name.of.the.package

在这里,您用每个包的名称来代替full.name.of.the.package。以单个#开头的行实际上代表 1 级标题。

文件的其余部分包含 Markdown 样式的文本。例如,包kotlinforandroid.book.numberguess.random中的package-info.md文件可以读为

# Package kotlinforandroid.book.numberguess.random

This package contains *interfaces* and *classes* for generating random numbers.

In your code you will write something like this:

     val rnd:RandomNumberGenerator = [ one of the 'impl' classes instantiated ]

For example,

     val rnd:RandomNumberGenerator = StdRandom()
     // or
     val rnd:RandomNumberGenerator = RandomRandom()

这些package-info.md文件和我们将在这里讨论的所有其他文档结构可以用来为您的项目生成文档。在这个过程中,*interface*将被翻译成强调的文本,行首有四个空格的段落将应用代码样式格式。反引号(')内的文本将被标记为内联代码。例如,这个特定的降价文件将被翻译成如图 6-3 所示的文档。下一节将描述这些以及所有其他标准的降价语法元素。

img/476388_1_En_6_Fig3_HTML.jpg

图 6-3。

翻译后的降价代码

减价

用于包描述的 Markdown 文件和 Kotlin 代码文件中的内联文档都使用通用的语法来处理样式问题。这些降价语法元素在表 6-1 中描述。

表 6-1。

降价语法

|

风格

|

降价语法

|

暗示

| | --- | --- | --- | | 标题级别 1 | # Heading | package-info.md文件不得包含一个以上的一级标题。您可以在标题行的末尾添加一个#。 | | 标题级别 2–6 | ## Heading``### Heading… | #的数量决定了等级。您可以通过在标题末尾追加相同数量的#来提高可读性。 | | 无序列表 | - Item1``- Item2… | 您也可以使用+或作为项目指示器。 | | 有序列表 | 1\. Item1``2\. Item2… | 连续编号将被自动确保,所以你可以写任何数字(写总是“1”或者别的什么)。 | | 强调 | *some text*或者_some text_ | 如果文本中需要星号()或下划线(),请写\*\_. | | 强烈强调 | **some text**或者_ _some text_ _ | 如果文本中需要星号(*)或下划线(),请写\*\_. | | 批量报价 | > some text | 您可以通过在行首使用更多>字符来提高级别。块引号可以包含其他降价元素。 | | 段落分隔符 | | 某些文本末尾的换行符不会结束一个段落。 | | 环 | 见下文 | — | | 内嵌代码 | 'some text'(反勾号) | 如果你在文本中需要一个反勾号('),写\'. | | 分组码 | t 0t 0… | 这必须用空行包围。⊔是一个空格字符(您也可以使用一个制表符代替)。 | | 规则 | - - -``* * * | 您也可以使用更多的这些字符,并使用空格字符作为分隔符。 | | 逃脱 | 前置一个"\" | 使用它来避免角色做一些特殊的事情,如表中前面所述。合格字符为\ * _ [ ] ( ) # + - . ! ' |

插入链接有几种选择。首先,您可以创建一个内联链接,如下所示:

[link text](link-URL)
or
[link text](link-URL "Title")

如果文档被转换成 HTML,那么可选的"Title"将进入title属性。例如,一旦鼠标悬停在链接上,就会向用户显示title属性(这种行为取决于所使用的浏览器)。以下是这种内联链接的一个示例:

Find the link here:
[Link](http://www.example.com/somePage.html "Page")

引用链接使用引用 ID,这样你就可以在一个文本中多次引用同一个链接。语法是

[link text][link ID]

其中link ID可以包含字母、空格、数字和标点符号,但不区分大小写。文本中的其他地方需要提供链接定义本身,单独占一行:

[link ID]: link-URL
or
[link ID]: link-URL "Title"

对于长 URL 或长标题,可选的"Title"也可以放在下一行。请注意,链接定义不产生任何输出,它们只是使 Markdown 文件中的文本更容易阅读。

作为一个缩写,链接文本可以作为文本和 ID,如果你写

[link text][]

对于这个定义

[link text]: link-URL
or
[link text]: link-URL "Title"

如果你不需要链接文本,只是想告诉网址,你应该把链接转换成自动链接,用尖括号把它们括起来,如< http://www.apress.com >。然后 URL 按原样打印出来,但也可以点击。

作为上述链接的扩展,您可以引用类、属性和方法,就像它们是隐式链接一样:

[com.example.TheClass]
[com.example.TheClass.property]
[com.example.TheClass.method]

对于接口和单例对象,也可以用同样的方法。如果您想提供自己的链接文本,请这样写:

[link text][com.example.TheClass]
[link text][com.example.TheClass.property]
[link text][com.example.TheClass.method]

如果被记录的元素可能通过它们的简单名称寻址类、接口或单例对象,因为它们已经被导入,那么可以省略包说明符,你可以直接写[TheClass][TheClass.property][TheClass.method].

班级评论

我们知道多行注释可以写成/* ... */。作为一个小小的修改,为了记录代码元素,惯例是在左边的注释括号中添加另一个星号(*):/** ... */,此外,注释中的每一行都应该以星号开头,如下所示:

/**
 *The comment ...
 * ...
 */

这仍然是一个碰巧以星号开始的多行注释,但是知道如何从代码中提取文档的工具认为这是需要处理的事情。你仍然可以随意使用普通的多行注释/* ... */,但是文档工具会忽略它们。

类注释就写在class ...声明的前面,这样一个改编的多行注释/** ... */。如前所述,类描述注释的内容是 Markdown 代码。

此类文档的第一段应该提供一个简短的摘要,因为工具可能会使用它来列出清单。除了标准降价元素之外,您还可以在文档中添加如下元素:

  • @param <name> description:描述类的类型参数<name>。类类型参数将在本书的后面描述。你也可以写@param[name] description

  • @constructor description:描述类的主构造函数。

  • @property <name> description:描述主构造函数的一个参数。

  • @sample <specifier>:插入指定功能的代码。

  • @see <specifier>:添加一个链接到指定的标识符(类、接口、单例对象、属性或方法)。

  • @author description:添加创作信息。

  • @since description:添加关于文档化元素已经存在多长时间的信息(版本信息等)。).

  • @suppress:从文档中排除类、接口或单例对象。

NumberGuessMainActivity类的文档示例

游戏是这样的:

/**
 * The main activity class of the NumberGuess game app.
 * Extends from the
 * [android.support.v7.app.AppCompatActivity]
 * class and is thus compatible with earlier
 * Android versions.
 *
 * The app shows a GUI with the following buttons:
 * - **Start**: Starts the game
 * - **Do Guess**: Used for guessing a number
 *
 * Once started, the game secretly determines a random
 * number the user has to guess. The user performs
 * guesses and gets told if the guessed number is too
 * low, too high, or a hit.
*
 * Once hit, the game is over.
*
 * @see Constants
*
 * @author Peter Späth
 * @since 1.0
 */
class MainActivity : AppCompatActivity() {
    ...
}

相应的输出,一旦被文档工具转换,将如图 6-4 所示。

img/476388_1_En_6_Fig4_HTML.jpg

图 6-4。

数字猜测活动的文档

函数和属性注释

对于函数和属性,您基本上可以像对待类一样进行操作。只要在任何你想注释的函数或者属性前面加上/** ... */就可以了。对于类文档,您可以用任意数量的空格和星号开始每一行。再次使用降价代码。例如:

...
class SomeClass {
    /**
    * This describes property prop
    * ...
    */
    val prop:Int = 7

    /**
     * This describes function func
     * ...
     */
    fun func() {
        ...
     }
}

至于类、接口和单例对象,这类文档的第一段应该提供一个简短的摘要,因为工具可能会用它来列出清单。

对于属性,您可以使用几个附加元素:

  • @sample <specifier>:插入指定功能的代码。

  • @see <specifier>:添加一个链接到指定的标识符(类、接口、单例对象、属性或方法)。

  • @author description:添加创作信息。

  • @since description:添加关于文档化元素已经存在多长时间的信息(版本信息等)。).

  • @suppress:从文件中排除遗产。

函数文档片段还应该描述函数的参数和返回值。具体来说,这里是函数的所有文档元素。

  • @param <name> description:描述一个函数参数。

  • @return description:描述函数返回的内容。

  • @receiver description:描述扩展功能的接收方。

  • @throws <specifier>:表示函数可能抛出由说明符指定的异常。我们将在本书的后面讨论异常。

  • @exception <specifier>:同@throws

  • @sample <specifier>:插入指定功能的代码。

  • @see <specifier>:添加一个链接到指定的标识符(类、接口、单例对象、属性或方法)。

  • @author description:添加创作信息。

  • @since description:添加关于文档化元素已经存在多长时间的信息(版本信息等)。).

  • @suppress:从文件中排除遗产。

练习 1

NumberGuess游戏 app 的所有包、类、公共函数添加评论。

生成您自己的 API 文档

当一个程序的所有元素都被恰当地文档化后,我们现在需要找到一种方法来提取文档,以便创建,例如,一个相互链接的 HTML 文档的集合。生成的文档应该描述所有的类、接口和单例对象,以及所有的公共方法和属性。因为这些元素足以让客户端软件知道如何与你的程序交互,所以这样的文档通常被称为应用编程接口(API)文档

Dokka 是 Kotlin 可以用来创建这种 API 文档的工具。要安装 Dokka,请打开 Android Studio。在 Gradle Scripts 抽屉里(你可能需要切换回 Android 视图类型),有两个名为build.gradle的文件,一个标记为 Project NumberGuess,一个标记为 Module: app(见图 6-5 )。这两个构建文件负责描述如何构建应用以正确运行。这包括声明需要对您的程序可用的库。

img/476388_1_En_6_Fig5_HTML.jpg

图 6-5。

构建脚本

注意

术语通常指其他人构建的程序,你的应用使用其中的部分来执行某些任务。您经常会将库添加到您的项目中,这样您就可以从其他人提供给公众的工作中受益。

打开项目build.gradle,在buildscript {下添加下面一行:

ext.dokka_version = '0.9.17'

在同一个文件中,在dependencies块内还添加(一行):

classpath "org.jetbrains.dokka:
       dokka-android-gradle-plugin:${dokka_version}"

这确保了 Dokka 库被添加到项目中。

现在打开 Moduĺe build.gradle,在所有其他应用插件行的下面,添加

apply plugin: 'org.jetbrains.dokka-android'

在同一个文件中,在底部添加以下内容:

task myDokka(type: org.jetbrains.dokka.gradle.
   DokkaAndroidTask) {
    outputFormat = 'html'
    outputDirectory = "dokka"
    includes = ['packages.md']
    doFirst {
        // build the packages.md file
        def pckg = new File(projectDir.absolutePath +
            File.separator + "packages.md")
        pckg.text = ""
        def s = ""
        projectDir.eachFileRecurse(
              groovy.io.FileType.FILES) { f ->
            if(f.name == 'package-info.md') {
                s += "\n" + f.text
            }
        }
        pckg.text = s
    }
}

这将配置 Dokka 并增加一个准备步骤。

注意

默认情况下,Dokka 不知道如何处理我们的package-info.md文件。相反,它期望一个单独的文件packages.md。准备步骤收集所有的package- info.md文件并建立一个packages.md文件。顺便说一下,这个小脚本是用 Groovy 编写的,这是 Gradle build 系统所依赖的语言。

现在实际执行文档生成,打开窗口最右边的 Gradle 选项卡,然后导航到 NumberGuess: ➤ NumberGuess ➤任务➤文档。双击 myDokka(参见图 6-6 )。

img/476388_1_En_6_Fig6_HTML.jpg

图 6-6。

Dokka 构建任务

现在,您会发现 API 文档是文件夹dokka中相互链接的 HTML 文件的集合(切换到 Project Files 视图类型,在 Android Studio 中查看)。