Perl6 如何决定加载哪个版本的模块?
How does Perl6 decide which version of a module gets loaded?
当我执行 use Foo:ver<1.0>;
时,它会加载模块 Foo
的 1.0 版。但是当我做 use Foo;
时会发生什么?
TL;DR: 当没有给定特定版本时,默认的 Perl6 安装将从它遇到的第一个 CompUnit::Repository
加载最新版本,该版本与该模块的任何版本匹配(不一定是所有版本中的最高版本) CompUnit::Repository
).
可以创建和加载非核心 CompUnit::Repository
除非另有说明,否则它本身只会加载模块的随机版本。此答案不适用于这些,并将重点放在各种核心 CompUnit::Repository
的行为和规范上。
决定加载哪个模块的第一件事是 CompUnit::Repository
首先匹配请求的身份。默认的存储库链看起来像这样:
# EXAMPLE 1
$ perl6 -e '.say for $*REPO.repo-chain'
inst#/home/ugexe/.perl6
inst#/home/ugexe/perl6/install/share/perl6/site
inst#/home/ugexe/perl6/install/share/perl6/vendor
inst#/home/ugexe/perl6/install/share/perl6
inst#
前缀告诉我们这是一个 CompUnit::Repository::Installation
。这是相关的,因为这样的回购可以包含多个发行版——包括同一发行版的多个版本——这对于用于 -I.
或 -Ilib
的单一发行版 CompUnit::Repository::FileSystem
是不正确的( 真的 -Ifile#/home/ugexe/repos/Foo
和 -Ifile#/home/ugexe/repos/Foo/lib
).
# EXAMPLE 2
$ perl6 -I. -e '.say for $*REPO.repo-chain'
file#/home/ugexe/repos/Foo
inst#/home/ugexe/.perl6
inst#/home/ugexe/perl6/install/share/perl6/site
inst#/home/ugexe/perl6/install/share/perl6/vendor
inst#/home/ugexe/perl6/install/share/perl6
假设如下:
file#/home/ugexe/repos/Foo
包含 Foo:ver<0.5>
inst#/home/ugexe/.perl6
包含 Foo:ver<0.1>
和 Foo:ver<1.0>
inst#/home/ugexe/.perl6
包含 Foo:ver<2.0>
和 Foo:ver<0.1>
use Foo;
将加载:
示例 1 - Foo:ver<1.0>
来自 inst#/home/ugexe/.perl6
示例 2 - Foo:ver<0.5>
来自 file#/home/ugexe/repos/Foo
即使所有存储库中的最高版本是 Foo:ver<2.0>
链中与 Foo 的 任何 版本匹配的第一个存储库(即 use Foo
) 获胜,因此永远不会选择 Foo:ver<2.0>
。您可能猜到这使得 "highest version" 成为决定加载模块版本的第二个因素,但它实际上是第四个因素!但是我在这里提到它是因为对于典型的使用来说这已经足够了。
决定加载模块版本的第二件事是 api
字段。这本质上是另一个版本字段,当与版本本身结合时,提供了一种固定主要版本的基本方法。
假设如下:
file#/home/ugexe/repos/Foo
包含 Foo:api<0>:ver<0.5>
inst#/home/ugexe/.perl6
包含 Foo:api<1>:ver<0.1>
和 Foo:api<0>:ver<1.0>
use Foo;
将加载:
示例 1 - Foo:api<1>:ver<0.1>
来自 inst#/home/ugexe/.perl6
示例 2 - Foo:api<0>:ver<0.5>
来自 file#/home/ugexe/repos/Foo
尽管在示例 1 中最高版本是 Foo:api<0>:ver<1.0>
,但最高 api 版本是 Foo:api<1>:ver<0.1>
,因此被选中。
决定加载模块版本的第三件事是 auth
字段。与 api
和 ver
不同,它并不意味着任何排序。而且与 api
和 ver
字段不同,您可能不应该在您的示例中使用它。 use Foo
-- 它以政策为重点,将成为 power-tool/escape 孵化器,希望大多数开发人员永远不必担心(滥用)使用。
假设如下:
file#/home/ugexe/repos/Foo
包含 Foo:auth<github:ugexe>:ver<0.5>
inst#/home/ugexe/.perl6
包含 Foo:ver<0.1>
和 Foo:auth<github:ugexe>:ver<1.0>
use Foo;
将加载:
示例 1 - Foo:auth<github:ugexe>:ver<1.0>
来自 inst#/home/ugexe/.perl6
示例 2 - Foo:auth<github:ugexe>:ver<0.5>
来自 file#/home/ugexe/repos/Foo
在这两个示例中,use Foo;
与 use Foo:auth(*):ver(*)
相同,因此即使其中一个回购假设包含一个没有 auth
的模块,但这并不意味着它是完全匹配的对于 use Foo;
。相反,:auth(*)
包含任何 auth
值作为匹配项(实际上意味着 auth
被完全忽略)。
有关更多示例,spec tests 是一个很好的来源
当我执行 use Foo:ver<1.0>;
时,它会加载模块 Foo
的 1.0 版。但是当我做 use Foo;
时会发生什么?
TL;DR: 当没有给定特定版本时,默认的 Perl6 安装将从它遇到的第一个 CompUnit::Repository
加载最新版本,该版本与该模块的任何版本匹配(不一定是所有版本中的最高版本) CompUnit::Repository
).
可以创建和加载非核心 CompUnit::Repository
除非另有说明,否则它本身只会加载模块的随机版本。此答案不适用于这些,并将重点放在各种核心 CompUnit::Repository
的行为和规范上。
决定加载哪个模块的第一件事是 CompUnit::Repository
首先匹配请求的身份。默认的存储库链看起来像这样:
# EXAMPLE 1
$ perl6 -e '.say for $*REPO.repo-chain'
inst#/home/ugexe/.perl6
inst#/home/ugexe/perl6/install/share/perl6/site
inst#/home/ugexe/perl6/install/share/perl6/vendor
inst#/home/ugexe/perl6/install/share/perl6
inst#
前缀告诉我们这是一个 CompUnit::Repository::Installation
。这是相关的,因为这样的回购可以包含多个发行版——包括同一发行版的多个版本——这对于用于 -I.
或 -Ilib
的单一发行版 CompUnit::Repository::FileSystem
是不正确的( 真的 -Ifile#/home/ugexe/repos/Foo
和 -Ifile#/home/ugexe/repos/Foo/lib
).
# EXAMPLE 2
$ perl6 -I. -e '.say for $*REPO.repo-chain'
file#/home/ugexe/repos/Foo
inst#/home/ugexe/.perl6
inst#/home/ugexe/perl6/install/share/perl6/site
inst#/home/ugexe/perl6/install/share/perl6/vendor
inst#/home/ugexe/perl6/install/share/perl6
假设如下:
file#/home/ugexe/repos/Foo
包含Foo:ver<0.5>
inst#/home/ugexe/.perl6
包含Foo:ver<0.1>
和Foo:ver<1.0>
inst#/home/ugexe/.perl6
包含Foo:ver<2.0>
和Foo:ver<0.1>
use Foo;
将加载:
示例 1 -
Foo:ver<1.0>
来自inst#/home/ugexe/.perl6
示例 2 -
Foo:ver<0.5>
来自file#/home/ugexe/repos/Foo
即使所有存储库中的最高版本是 Foo:ver<2.0>
链中与 Foo 的 任何 版本匹配的第一个存储库(即 use Foo
) 获胜,因此永远不会选择 Foo:ver<2.0>
。您可能猜到这使得 "highest version" 成为决定加载模块版本的第二个因素,但它实际上是第四个因素!但是我在这里提到它是因为对于典型的使用来说这已经足够了。
决定加载模块版本的第二件事是 api
字段。这本质上是另一个版本字段,当与版本本身结合时,提供了一种固定主要版本的基本方法。
假设如下:
file#/home/ugexe/repos/Foo
包含Foo:api<0>:ver<0.5>
inst#/home/ugexe/.perl6
包含Foo:api<1>:ver<0.1>
和Foo:api<0>:ver<1.0>
use Foo;
将加载:
示例 1 -
Foo:api<1>:ver<0.1>
来自inst#/home/ugexe/.perl6
示例 2 -
Foo:api<0>:ver<0.5>
来自file#/home/ugexe/repos/Foo
尽管在示例 1 中最高版本是 Foo:api<0>:ver<1.0>
,但最高 api 版本是 Foo:api<1>:ver<0.1>
,因此被选中。
决定加载模块版本的第三件事是 auth
字段。与 api
和 ver
不同,它并不意味着任何排序。而且与 api
和 ver
字段不同,您可能不应该在您的示例中使用它。 use Foo
-- 它以政策为重点,将成为 power-tool/escape 孵化器,希望大多数开发人员永远不必担心(滥用)使用。
假设如下:
file#/home/ugexe/repos/Foo
包含Foo:auth<github:ugexe>:ver<0.5>
inst#/home/ugexe/.perl6
包含Foo:ver<0.1>
和Foo:auth<github:ugexe>:ver<1.0>
use Foo;
将加载:
示例 1 -
Foo:auth<github:ugexe>:ver<1.0>
来自inst#/home/ugexe/.perl6
示例 2 -
Foo:auth<github:ugexe>:ver<0.5>
来自file#/home/ugexe/repos/Foo
在这两个示例中,use Foo;
与 use Foo:auth(*):ver(*)
相同,因此即使其中一个回购假设包含一个没有 auth
的模块,但这并不意味着它是完全匹配的对于 use Foo;
。相反,:auth(*)
包含任何 auth
值作为匹配项(实际上意味着 auth
被完全忽略)。
有关更多示例,spec tests 是一个很好的来源