跳至內容

引入檔案

在單一檔案中撰寫程式碼對於小型程式片段和小基準測試程式碼來說是可以的。大型程式碼若分散在不同的檔案中,則會更容易維護和理解。

若要讓編譯器處理其他檔案,您可以使用 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}" 內部,每個專案的目錄都存在(srcspecREADME.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" 的檔案,則會引入該檔案。
  • 否則會發出編譯時期錯誤。

此相對位置主要用於專案內部,以參照其中的其他檔案。它也用於參照來自 規格 的程式碼

spec/spec_helper.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" 內部的目錄下的檔案。