我的问题与require在用于所需名称空间的静态或动态解析时的行为有关。
我会试着表达我对事物的理解:
[1]使用需要字面
{ require MODULE; }
在本例中,编译器检查模块是否已声明为符号。如果没有,编译器会声明它,并将它绑定到一个空的占位符包,它是为这个“require”创建的
{
my $response = ::('MODULE'); # this happens at runtime
say $response.^name; # MODULE doesn't exist so the lookup results in the compilation-phase placeholder package: MODULE
try require MODULE; # although the execution order of require comes after the lookup,
# the placeholder package creation was done during compilation and the package is present in the current scope during run-time
}
[2]使用需要与字符串
{ try require 'FILE_PATH'; }
在这种情况下,“要求”是试图找到(在运行时)由字符串中声明的文件名定义的文件。如果找到(包含适当的内容:模块、包等),它将在当前作用域中创建一个命名空间,并将其加载为文件的内容。
[3]在动态查找中使用“require”
{ try require ::('MODULE'); }
在我看来,在这种情况下,“require”的行为不像“普通”子例程。
当我们将“require”与“dynamiclookup”一起使用时,动态查找的核心功能在一个新的例程中“融化”,该例程的行为与我们预期的不同。
事实上,“动态查找”例程的结果要么是符号,要么是失败。
如果“要求”的行为类似于“普通”子例程,那么它可以使用的唯一输入将是随后的动态查找(命名空间或失败)的结果。
但是在失败的情况下(作为动态查找的结果),“需要”继续在存储库中搜索合适的包(通常情况下,仍然使用我们给动态查找的参数:“模块”),这也是一个事实。
所以很明显,“要求”在这个意义上并不像一个“正常”的子程序。
根据我的思路,需求动态查找的组合类似于以下结构:
{ modified_dynamic_lookup('MODULE') :if_symbol_not_found_search_repositories_and_if_appropriate_package_found_create_namespace_and_load_package_contents; }
我关心的是我对案例[3]的理解。
需要动态查找是如何工作的?(从分析角度讲,编译器首先要遵循哪些步骤,然后才是运行时?)
[后脚本]
我同意@raiph的观点,即“require”不是一个子程序,它与语言有着深刻的整合。
从这个意义上讲,require“指令”后面的“动态查找结构”用于两件事:
>
通知编译器该构造是“动态的”(因此不必在编译时修复任何东西)
提供用于搜索符号、名称空间、文件或存储库内容的字符串
@raiph表示,他认为“require”在成功加载后进行查找。
我唯一的反对意见是,当我们加载同一个库时,“require”不会引发任何异常。
它是否会自动忽略加载的库?当它可以首先检查同一名称空间是否已经在使用时,为什么还要费心做这么多工作呢?
相反,当我们假装加载了另一个库时,它会抛出一个异常:“重复定义”正在使用的符号。
为了证明我进行了以下操作:
在./lib目录中,我放置了两个库,“foo.pm6”是“foo”的单元定义,其中定义了一个类A:
file "foo.pm6" contents:
-----------------------------------
unit module foo;
class A is export {}
另一个库“other.pm6”,它有一个“foo”的定义,这次定义了一个不同的B类。
file "other.pm6" contents:
-----------------------------------
module foo {
class B is export {}
}
raku程序文件包含以下内容:
use lib <lib>;
my $name = 'other'; # select one of {'other', 'foo'}
require ::('foo') <A>; ########> Initial package loading
my $a = try ::('foo::A').new;
say '(1) ' ~ $a.^name; # (1) foo::A
$a = ::('A').new;
say '(2) ' ~ $a.^name; # (2) foo::A
try require ::($name); # if $name eq 'other' => throws exception, if $name eq 'foo' => does nothing
with $! {.say}; # P6M Merging GLOBAL symbols failed: duplicate definition of symbol foo ...
$a = try ::('foo::A').new;
say '(3) ' ~ $a.^name; # (3) foo::A
$a = ::('A').new;
say '(4) ' ~ $a.^name; # (4) foo::A
从上面的例子我们可以看到,当我们尝试重新加载foo命名空间时,隐藏在一个不同名称的文件中(只是为了欺骗raku),它会抛出一个异常。
因此,我得出结论,可能“require”首先检查与所提供字符串具有相同名称的名称空间。
顺便说一句,在检查这件事时,我偶然发现了一种奇怪的行为。以下是:
如果我们在“初始包加载”中使用“使用foo;”,而不是“e::(“foo”);”,我们会得到以下结果:
(1) foo::A
(2) foo::A
No such symbol 'other' ...
(3) Any
(4) foo::A
在(3)中查找foo::A没有找到任何东西!!!
此外,如果我将库文件“other.pm6”更改为以下内容(类A而不是foo.pm6中的类B)
file "other.pm6" contents:
-----------------------------------
module foo {
class A is export {}
}
结果似乎回到了预期:
(1) foo::A
(2) foo::A
No such symbol 'other' ...
(3) foo::A
(4) foo::A
是一只虫子还是我遗漏了什么?
require
可以在编译过程中执行一些操作。
require Module;
say Module;
它假定加载该模块将为您提供名为module
的内容。
因此,它会在编译时安装一个具有该名称的临时符号。
这是它在编译时唯一做的事情<(所以当我说“一些”时,我撒了个小谎
if Bool.pick {
require module-which-does-not-exist;
module-which-does-not-exist.method-call()
}
大约有一半的时间,上面所说的什么都不做
它在运行时抱怨找不到模块的另一半时间。
(我选择了Bool.pick
而不是False
,因此编译时优化器肯定无法对其进行优化。)
当您用标识符以外的东西调用它时,它在编译时不知道模块将是什么。因此它无法创建临时名称空间。
require 'Module';
say Module; # COMPILE ERROR: undeclared name
require Module; # RUNTIME ERROR: can't find 'Module'
say Module;
require 'Module'; # RUNTIME ERROR: can't find 'Module'
say ::('Module');
if False {
require Module;
say Module;
}
# no error at all
if False {
require 'Module';
say ::('Module');
}
# no error at all
重写以对应于您答案的第三个版本。
在这种情况下,编译器将检查模块
是否已声明为符号。如果没有,编译器会声明它,并将它绑定到一个空的占位符包,它是为这个“require”创建的
更具体地说,require
关键字以及由它生成的代码4起作用。
它创建符号的唯一原因是,人们可以编写标识符,代码将被编译。如果require
没有这样做,那么使用标识符的代码将无法编译,即使require FOO
会成功:
require FOO;
my FOO $bar; # Type 'FOO' is not declared
#模块不存在,因此在编译阶段占位符包中查找结果:模块
MODULE
确实存在。查找成功。它返回绑定到MODULE
符号的值,该符号是在编译阶段需要
放在那里的占位符包。
#虽然需要
的执行顺序在查找之后
执行需要
的编译阶段操作在运行阶段发生的查找之前。
如果找到(包含适当的内容:模块、包等),那么它将在当前范围内创建一个名称空间,并使用文件的内容加载它。
我认为require
符号的唯一声明是代码编写器作为require
语句的一部分显式编写的静态标识符。示例:
>
require模块
需要'MODULE. pm6'
require::(“模块”)
Aiui MLS1,作为符号合并(P6M)的一部分,根据需要声明更多符号。但是这项工作不是由
require
完成的。这是由MLS代表它做的。而且它不是require
所特有的。这与编译阶段由于use
语句而发生的工作是相同的。
{ try require ::('MODULE'); }
我有一段代码试图证明,在尝试加载模块之前,这不会进行查找2
在我看来,在这种情况下,“require”的行为不像“普通”子例程。
require
不是例行程序,正常或其他。
say require MODULE; # Undeclared name:
MODULE used at line 1
# Undeclared routine:
require used at line 1
如果您在官方文档中搜索
需要
,您会看到它没有列在常规参考部分,而是列在语言参考的模块部分。它是一个关键字,一个语句,编译器理解的语言的一个特殊部分。
如果“要求”的行为类似于“普通”子例程,那么它可以使用的唯一输入将是随后的动态查找(命名空间或失败)的结果。
动态查找的结果是绑定到符号(如果已声明)的值,或者
失败
否则:
my $variable = 42;
say ::('$variable'); # 42
say ::('nonsense') ~~ Failure; # True
$variable
不是命名空间。
但是在失败的情况下(作为动态查找的结果),“需要”继续在存储库中搜索合适的包(通常情况下,仍然使用我们给动态查找的参数:“模块”),这也是一个事实。
考虑到我编写的跟踪动态查找:('MODULE')2值的代码,在我看来,如果模块加载失败,无论是
require
还是MLS,都可能没有任何代码对其进行动态查找。
这反过来意味着它只会在模块加载期间或之后(成功加载)发生。因此,要么MLS正在这样做(似乎最有可能),要么,
require
在模块成功加载后正在这样做(似乎不太可能,但我还没有准备好100%消除它)。
{modified_dynamic_lookup('MODULE'):if_symbol_not_found_search_repositories_和if_if_property_package_found_创建_namespace_和_load_package_contents;}
我想我已经证明了要么根本没有
要求
或MLS的查找,要么,如果它这样做了,它只是在成功加载模块之后。
编译器首先遵循哪些步骤,然后是运行时遵循哪些步骤?
这个答案当然是试图回答这个问题,但我的简短编译器代码分析可能会有所帮助3(点击链接查看
操作中的实际代码。nqp
不适用于心脏虚弱者!)
从这个意义上讲,require“指令”后面的“动态查找结构”用于两件事:
>
通知编译器该构造是“动态的”(因此不必在编译时修复任何东西)
提供用于搜索符号、名称空间、文件或存储库内容的字符串
我认为它只做2,只是一个传递给MLS的包名称。
当我们加载同一个库时,“require”不会引发任何异常。它是否会自动忽略加载的库?
我认为
require
对此一无所知。它把它交给大联盟,然后在大联盟完成任务后再接。我认为require
无法区分MLS何时成功地进行了新加载,何时跳过了加载。它只知道MLS是说一切都好还是有例外。
当它可以首先检查相同的命名空间已经在使用时,为什么要费心做这么多工作呢?
既然MLS已经做了任何工作,而且
require
无论如何都要调用MLS,为什么还要费心去做这些工作呢?做任何事都是白费力气。
require
所要做的就是处理用户在require
语句中显式键入的编译阶段符号。它不能要求MLS处理这些问题,因为这与成功加载模块无关,而这是MLS处理符号的唯一情况。
相反,当我们假装加载了另一个库时,它会抛出一个异常:“重复定义”正在使用的符号。
试试这个:
require ::('foo');
require ::('other');
现在,当您更改
单元模块foo
在
foo中。pm6和其他。pm6
至单元模块条
。您仍然会得到相同的异常,但符号将是
条
。如何要求
了解条码
?不能。例外情况来自MLS,符号只有MLS知道。
因此,我得出结论,可能“require”首先检查与所提供字符串具有相同名称的名称空间。
除非您将MLS计算为
require
的一部分,否则我相信您现在可以看到您的“可能”资格是明智的:
我偶然发现一种奇怪的行为。。。在(3)中查找'foo::A'没有找到任何内容!!!
我有一个解释。我并不是说这是对的,但在我写这篇文章时,我觉得这并不奇怪:
use
语句加载foo。pm6
包装。它定义了一个包foo
,其中包含一个类a
,并导出a
。这将导致导入词法范围foo
中出现一个符号,该符号绑定到一个包,该包包含一个符号a
。它还导致导入词法范围中的另一个符号,A
。
require
语句加载other。pm6
包装。它定义一个包foo
,其中包含一个类B
,并导出B
。这将导致将导入词法范围中的foo
符号重新绑定到另一个包,即包含符号B
的新包。它还导致导入词法范围中的另一个符号,B
。
前面的
A
挂起。(换句话说,P6M符号合并过程不包括删除符号。)但是在绑定到foo
符号的包中查找的foo::A
不再存在,因为绑定到foo
符号的包现在是另一个中的包。pm6
包,覆盖了来自foo的包。pm6
包装。
与此同时,还有另一个奇怪之处:
try require ::($name);
with $! {.say}; # No such symbol 'other' ...
我认为这反映了在成功的模块加载后需要进行(失败的)查找。
请注意,如果模块未能加载,则不会显示此消息;这似乎再次证实了我的想法(代码2),即
require
在成功加载之前不会进行任何查找(如果是这样的话;我仍然不清楚是MLS在做这些事情还是require
;代码4对我来说太复杂了)。
从你对这个答案的评论来看:
它就像我们得到的结果,需要'动态查找公式'的合并,一个增强的动态查找像这样
{::('something'):如果没有找到\u作为\u名称空间\u检查\u存储库\u和\u加载}
由于种种原因,这对我来说似乎不是真的。
例如,假定有一个包<代码> FoO <代码>声明为“代码>模块FoO {我们的子条是导出{ 99 } } /代码>如果<代码>要求< /代码>,将成功加载。现在考虑这个代码:
my \foo = 42;
say ::('foo'); # 42
require ::('foo') <&bar>;
say foo; # 42
bar; # 99
这对我来说很有意义。它不会加载名为
42
的包。它不会查找符号foo
。它将加载名为foo
的包。虽然它可能会在加载包后查找symbolfoo
,但它不会安装symbolfoo
,因为已经有一个了。
1通过模块加载子系统,我指的是在给定模块名称的情况下,执行搜索本地文件系统或数据库、检查预编译目录、调用编译以及在模块成功加载时合并符号等操作的各个部分。我不知道部件之间的界限在哪里,部件和编译器之间的界限在哪里。但我相信它们不是
require
的一部分,而只是由它调用。
2运行此代码:
my \MODULE =
{ my $v;
Proxy.new:
FETCH => method { say "get name: $v"; $v },
STORE => method ($n) { say "set name: $n"; $v = $n }}();
MODULE = 'unseen by `require`';
say ::('MODULE');
use lib '.';
say 'about to `require`';
require ::('MODULE');
3我们从Raku的
语法中的相关匹配开始。nqp
文件:
rule statement_control:sym<require> {
<sym>
[
| <module_name>
| <file=.variable>
| <!sigil> <file=.term>
]
<EXPR>?
}
代码似乎遵循了我们所期望的-一个
要求
关键字,然后是:
>
a
a
我们对
token name {
[
| <identifier> <morename>*
| <morename>+
]
}
显然,
:('foo')
不是以
token morename {
'::'
[
|| <?before '(' | <.alpha> >
[
| <identifier>
| :dba('indirect name') '(' ~ ')' [ <.ws> <EXPR> ]
]
]?
}
答对 了这将匹配
::(
),尤其是:dba('indirect name')('~')[
因此,在这一点上,我们将捕获:
statement_control:sym<require><module_name><longname><name><morename><EXPR>
不久之后,
语句\u控件:sym
4在
Actions.nqp
中,我们找到对应于令牌statement_control:sym的操作
$longname := $*W.dissect_longname($<module_name><longname>);
$target_package := $longname.name_past;
在我看来,这段代码正在剖析解析
::('foo')
的结果,并将对应于该剖析的AST绑定到$target_package
,而不是费心进行查找或准备运行时查找。
如果我是对的,那么
::('foo')
不需要超过9个字符,而需要
来解释它们,尽管它喜欢解释它们。这里没有必要暗示它在构造包加载代码时会执行任何特定的操作,例如查找。
动作的后半部分进行查找。有这样几行:
?? self.make_indirect_lookup($longname.components())
给定例程名称,我假设它正在进行查找,可能是where
require
尝试添加包符号的一部分,如果包加载成功。
问题内容: 在我的数据库的多个地方,开发人员使用了动态sql而不是静态sql。他们说这是为了提高性能。有人可以告诉我动态sql是否真的可以提高存储过程或plsql块的性能吗? 哪个执行速度更快,为什么? 1。 2。 问题答案: 您的示例代码非常简单,几乎没有什么区别,但是在那种情况下,静态版本最有可能执行得更好。 使用动态SQL来提高性能的主要原因是,当SQL语句发生重大变化时- 例如,您可以根据
要求:在移动设备上查看基于XFA的PDF。 我尝试过的选项: 由于Adobe移动阅读器不支持XFA,因此我可以将XFA展平为静态PDF。我尝试过,但无法使用iText将动态XFA转换为静态PDF。 后来我尝试使用“Adobe PDF”作为打印服务打印XFA表单。这在手动执行时可以正常工作,但在通过代码执行时会以某种方式清除表单数据。 下面是打印任务的示例代码。已为“Adobe PDF”打印服务安装
我是新手,请放心。目前,我正在使用放心的API自动化。我有以下方案要处理 我们有两个 API(例如:API1、API2),API1 会给出用户详细信息的列表。我需要将这些详细信息作为第二个 API 请求的一部分发送。 API1 -响应 API2 -请求:。:在API2请求中,我需要发送“sourceUserId”和“source”详细信息。 userSourceMeta详细信息会根据用户动态变化。
问题内容: 在Linux上的“ C”上, 我需要静态库来静态链接,还是需要足够的共享库?如果没有,为什么不呢?(它们不包含相同的数据吗?) 问题答案: 是的,您需要静态库来构建静态链接的可执行文件。 静态库是编译对象的捆绑包。静态链接到库时,实际上与获取该库的编译结果,将它们解压缩到当前项目中以及将它们当作自己的对象使用一样。 动态库已链接。这意味着一些信息,例如重定位,已经被修复并丢弃。 此外,
上面是一段代码,它以某种形式出现在我即将进行的一次考试的过去试卷中。这个问题的想法是衡量你是否完全理解多态性,动态和静态铸造。面向对象的基本思想。 我想把我认为正确的东西拿出来,如果人们能纠正我或补充一点,我将不胜感激。 我看不出任何与上面代码相关的其他观点。
一个机器或语言是用来计算的,根据计算机模型的定义,其操作的是存储器里的数据,就现在流行的用二进制实现的计算机中(曾出现过三进制计算机),数据本质都是0和1,但机器毕竟是为人服务的,解决的是现实问题,它操作的数据需要有现实的含义,所以基本上所有语言都有类型系统,即便是汇编和机器语言,也有整数和浮点的区别 类型系统是很复杂的理论,值得用一本厚书来写,好点的资料有《类型与程序设计语言》,但我没看懂,因为