需要文件¶
在一个文件中编写程序对于小的代码片段和小的基准测试代码是可以的。大型程序在跨多个文件拆分时更容易维护和理解。
要让编译器处理其他文件,请使用 require "..."
。它接受一个参数,一个字符串字面量,它可以有多种形式。
一旦一个文件被需要,编译器就会记住它的绝对路径,之后对同一个文件的 require
将被忽略。
require "filename"¶
这将在需要路径中查找 "filename"。
默认情况下,需要路径包括两个位置
- 相对于当前工作目录的
lib
目录(这是查找依赖项的位置) - 编译器附带的标准库的位置
这些是唯一被查找的地方。
编译器使用的确切路径可以通过 crystal env CRYSTAL_PATH
查询
$ crystal env CRYSTAL_PATH
lib:/usr/bin/../share/crystal/src
这些查找路径可以通过定义 CRYSTAL_PATH
环境变量 来覆盖。
查找过程如下
- 如果在需要路径中找到名为 "filename.cr" 的文件,则需要该文件。
- 如果找到名为 "filename" 的目录,并且它直接包含名为 "filename.cr" 的文件,则需要该文件。
- 如果找到名为 "filename" 的目录,其中包含一个名为 "src" 的目录,并且它直接包含名为 "filename.cr" 的文件,则需要该文件。
- 否则,将发出编译时错误。
第二个规则意味着除了有这个
- project
- src
- file
- sub1.cr
- sub2.cr
- file.cr (requires "./file/*")
你也可以有这个
- project
- src
- file
- file.cr (requires "./*")
- sub1.cr
- sub2.cr
这可能有点更干净,这取决于你的品味。
第三个规则非常方便,因为它是项目的典型目录结构
- project
- lib
- foo
- src
- foo.cr
- bar
- src
- bar.cr
- src
- project.cr
- spec
- project_spec.cr
也就是说,在 "lib/{project}" 中,每个项目的目录都存在(src
、spec
、README.md
等等)
例如,如果你在 project.cr
中放置 require "foo"
,并在项目的根目录中运行 crystal src/project.cr
,它将在 lib/foo/foo.cr
中找到 foo
。
第四个规则是第三个规则应用于第二个规则。
如果你从其他地方运行编译器,比如 src
文件夹,lib
将不在路径中,require "foo"
无法解析。
require "./filename"¶
这将在包含 require 表达式的文件相对于该文件的位置查找 "filename"。
查找过程如下
- 如果在当前文件相对于当前文件的位置找到名为 "filename.cr" 的文件,则需要该文件。
- 如果找到名为 "filename" 的目录,并且它直接包含名为 "filename.cr" 的文件,则需要该文件。
- 否则,将发出编译时错误。
这种相对路径主要用于项目内部引用项目内部的其他文件。它也用于引用来自 规范 的代码
require "../src/project"
其他形式¶
在这两种情况下,你都可以使用嵌套名称,它们将在嵌套目录中被查找
require "foo/bar/baz"
将在需要路径中查找 "foo/bar/baz.cr"、"foo/bar/baz/baz.cr"、"foo/src/bar/baz.cr" 或 "foo/src/bar/baz/baz.cr"。require "./foo/bar/baz"
将在当前文件相对于当前文件的位置查找 "foo/bar/baz.cr" 或 "foo/bar/baz/baz.cr"。
你也可以使用 "../" 来访问相对于当前文件的父目录,因此 require "../../foo/bar"
也能正常工作。
在所有这些情况下,你可以使用特殊的 *
和 **
后缀
require "foo/*"
将需要 "foo" 目录下的所有 ".cr" 文件,但不包括 "foo" 内部目录下的文件。require "foo/**"
将需要 "foo" 目录下的所有 ".cr" 文件,以及 "foo" 内部目录下的所有 ".cr" 文件,递归地。