这些例程定义在不同的文件中,与一个或多个其他类一起,但实际上没有附加到任何特定的类或角色。
例程 EVAL§
proto EVAL( where Blob|Cool|Callable, Str() : = 'Raku',PseudoStash :, Str() :, Bool() :, *)
multi EVAL(, Str : where ,PseudoStash :, Str() :, :)
此例程在运行时执行一段代码片段 $code
,该代码片段属于给定的语言 $lang
,默认值为 Raku
。
它将 Cool
$code
强制转换为 Str
。如果 $code
是一个 Blob
,它将使用与 $lang
编译器相同的编码进行处理:对于 Raku
$lang
,使用 utf-8
;对于 Perl5
,使用与 Perl 相同的规则进行处理。
这适用于字面字符串参数。默认情况下,更复杂的输入(例如包含嵌入代码的变量或字符串)是非法的。这可以通过多种方式覆盖。
use MONKEY-SEE-NO-EVAL; # Or...use MONKEY; # shortcut that turns on all MONKEY pragmasuse Test;my = 0;my = 10;my Str = '$init += ' ~ ; # contains a Str object with value '$init += 10'# any of the above allows:EVAL ;EVAL ;say ; # OUTPUT: «20»
如果未激活 MONKEY-SEE-NO-EVAL
编译指示,编译器将使用 EVAL is a very dangerous function!!!
异常进行抱怨。它本质上是正确的,因为这将以与程序相同的权限运行任意代码。如果您激活了 MONKEY-SEE-NO-EVAL
编译指示,则应注意清理将通过 EVAL 传递的代码。
请注意,您可以使用引号来插值以创建例程名称,如 此示例 或 其他插值方式来创建标识符名称 所示。但是,这仅适用于已声明的函数和其他对象,因此使用起来更安全。
当前词法作用域中的符号对 EVAL
中的代码可见。
my = 42;EVAL 'say $answer;'; # OUTPUT: «42»
但是,由于词法作用域中的符号集在编译后是不可变的,因此 EVAL
永远不会将符号引入周围的作用域。
EVAL 'my $lives = 9'; say ; # error, $lives not declared
此外,EVAL
在当前包中进行评估。
say ::answer; # OUTPUT: «42»
并且还在当前语言中进行评估,这意味着任何添加的语法都可用。
sub infix:<mean>(*) is assoc<list>EVAL 'say 2 mean 6 mean 4'; # OUTPUT: «4»
EVAL
语句的值为最后一条语句的结果。
sub infix:<mean>(*) is assoc<list>say EVAL 'say 1; 2 mean 6 mean 4'; # OUTPUT: «14»
EVAL
也是执行其他语言代码的网关。
EVAL "use v5.20; say 'Hello from perl!'", :lang<Perl5>;
您需要安装 Inline::Perl5
才能使它正常工作。
更多语言可能通过其他模块得到支持,这些模块可以在 Raku 模块目录 中找到。
如果给出了可选的 $filename
参数,则 $?FILE
变量将设置为其值。否则,$?FILE
将设置为一个唯一且生成的文件名。
use MONKEY-SEE-NO-EVAL;EVAL 'say $?FILE'; # OUTPUT: «/tmp/EVAL_0»EVAL 'say $?FILE', filename => '/my-eval-code'; # OUTPUT: «/my-eval-code»
如果可选的 $check
参数为 True
,则 $code
将由 $lang
编译器处理,但实际上不会运行。对于 Raku
,BEGIN
和 CHECK
块将被运行。如果编译成功,EVAL
例程将返回 Nil
,否则将抛出异常。
子例程 EVALFILE§
sub EVALFILE( where Blob|Cool, : = 'Raku', :)
吸入指定文件并对其进行评估。在 Blob
解码、作用域、$lang
参数和 $check
参数方面,其行为与 EVAL
相同。当 $check
不为 True
时,评估结果为文件中最后一条语句产生的值。
EVALFILE "foo.raku";
子例程 repl§
注意:repl
是在 Rakudo 编译器 2021.06 版本中引入的。
sub repl()
暂停执行并进入当前上下文中 REPL(读-评估-打印循环)。此 REPL 与您运行 raku
没有任何参数 时创建的 REPL 完全相同,只是您可以访问/修改程序的当前上下文(例如词法变量)。
例如,如果您运行以下代码
my = "Alice";say "Hello, $name";repl();say "Goodbye, $name"
那么您将得到输出 Hello, Alice
,然后进入 REPL 会话(在打印任何包含“goodbye”的输出之前)。您的 REPL 会话可能如下所示
Type 'exit' to leave
[0] > $name
Alice
[1] > $name = "Bob"
Bob
[2] > exit
退出 REPL 会话后,Raku 将继续运行程序;在此运行期间,您在 REPL 会话中所做的任何更改仍然有效。因此,在上述会话之后,您将得到输出 Goodbye, Bob
而不是 Goodbye, Alice
,因为如果没有 REPL 会话,您将得到 Goodbye, Alice
。
子例程 get§
multi get (IO::Handle = )
此例程是 IO::Handle
中同名方法 的包装器。如果没有指定 Handle
,则默认为 $*ARGFILES
。
sub getc§
multi getc (IO::Handle = )
此例程是 IO::Handle
中同名方法 的包装器。如果没有指定 Handle
,则默认为 $*ARGFILES
。
sub mkdir§
sub mkdir(IO() , Int() = 0o777 --> IO::Path)
创建一个新目录;有关 $mode
的解释和有效值,请参见 mode
。成功时返回指向新创建目录的 IO::Path
对象;如果无法创建目录,则会 失败 并返回 X::IO::Mkdir
。
还会根据需要创建父目录(类似于带有 -p
选项的 *nix 实用程序 mkdir
);也就是说,mkdir "foo/bar/ber/meow"
将创建 foo
、foo/bar
和 foo/bar/ber
目录(如果它们不存在),以及 foo/bar/ber/meow
。
sub chdir§
sub chdir(IO() , : = True, :, :, : --> IO::Path)
将 $*CWD
变量的值更改为提供的 $path
,并可选地确保新路径通过几个文件测试。注意:此例程不会更改进程的当前目录(请参见 &*chdir
)。
成功时返回表示新 $*CWD
的 IO::Path
。失败时返回 Failure
并保持 $*CWD
不变。$path
可以是任何具有返回 IO::Path
对象的 IO 方法的对象。可用的文件测试是
默认情况下,只执行 :d
测试。
chdir '/tmp'; # change $*CWD to '/tmp' and check its .d is Truechdir :r, :w, '/tmp'; # … check its .r and .w are Truechdir '/not-there'; # returns Failure
请注意,以下结构是错误的
# WRONG! DO NOT DO THIS!my = chdir '/tmp/';
请改用 indir
。
sub &*chdir§
PROCESS::<&chdir> = sub (IO() --> IO::Path)
将 $*CWD
变量的值更改为提供的 $path
,并将进程的当前目录设置为 $path.absolute
的值。注意:在大多数情况下,您应该改用 chdir
例程。
成功时返回表示新 $*CWD
的 IO::Path
。失败时返回 Failure
并保持 $*CWD
不变。$path
可以是任何具有返回 IO::Path
对象的 IO 方法的对象。
请注意,与常规 chdir
不同,没有参数来指定要执行哪些文件测试。
('/tmp'); # change $*CWD and process's current directory to '/tmp'('/not-there'); # returns Failure
请注意,以下结构是错误的
# WRONG! DO NOT DO THIS!my = ('/tmp');
请改用以下方法;或者,如果您不需要更改进程的当前目录,请参见 indir
temp ;('/tmp');
sub chmod§
sub chmod(Int() , * --> List)
将所有 @filenames
强制转换为 IO::Path
,并对它们调用 IO::Path.chmod
,并使用 $mode
。返回一个 List
,其中包含对 chmod
成功执行的 @filenames
的子集。
chmod 0o755, <myfile1 myfile2>; # make two files executable by the owner
sub indir§
sub indir(IO() , , : = True, :, :, :)
接受 Callable
&code
,并在本地(对 &code
)将 $*CWD
变量更改为基于 $path
的 IO::Path
对象后执行它,并可选地确保新路径通过几个文件测试。如果 $path
是相对路径,它将被转换为绝对路径,即使给出了 IO::Path
对象。注意:此例程不会更改进程的当前目录(请参见 &*chdir
)。&code
外部的 $*CWD
不会受到影响,即使 &code
明确地为 $*CWD
分配了新值。
成功时返回 &code
调用返回的值。如果无法成功更改 $*CWD
,则返回 Failure
。警告:请记住,延迟评估的事物最终可能在实际评估时没有 indir
在其动态作用域中设置的 $*CWD
。请确保生成器设置了它们的 $*CWD
,或者在从 indir
返回结果之前 急切地评估 它们。
say indir("/tmp",)».CWD; # OUTPUT: «(/home/camelia)»say indir("/tmp",)».CWD; # OUTPUT: «(/tmp)»say indir("/tmp",)».CWD; # OUTPUT: «(/tmp)»
例程的 $path
参数可以是任何具有返回 IO::Path
对象的 IO 方法的对象。 可用的文件测试是
默认情况下,只执行 :d
测试。
say ; # OUTPUT: «"/home/camelia".IO»indir '/tmp', ; # OUTPUT: «"/tmp".IO»say ; # OUTPUT: «"/home/camelia".IO»indir '/not-there', ; # returns Failure; path does not exist
子例程 print§
multi print(** --> True)multi print(Junction --> True)
将给定文本打印到标准输出($*OUT
文件句柄),通过调用 .Str
方法 将非 Str
对象强制转换为 Str
。 Junction
参数 自动线程化,打印字符串的顺序不保证。
print "Hi there!\n"; # OUTPUT: «Hi there!»print "Hi there!"; # OUTPUT: «Hi there!»print [1, 2, 3]; # OUTPUT: «1 2 3»print "Hello" | "Goodbye"; # OUTPUT: «HelloGoodbye»
要打印文本并包含尾随换行符,请使用 put
。
子例程 put§
multi put()multi put(** --> True)multi put(Junction --> True)multi put(Str \x)multi put(\x)
与 print
相同,只是它使用 print-nl
(默认情况下打印 换行符)在末尾。 Junction
参数 自动线程化,打印字符串的顺序不保证。
put "Hi there!\n"; # OUTPUT: «Hi there!»put "Hi there!"; # OUTPUT: «Hi there!»put [1, 2, 3]; # OUTPUT: «1 2 3»put "Hello" | "Goodbye"; # OUTPUT: «HelloGoodbye»
put()
本身将打印一个新行
put "Hey"; put(); put("Hey"); # OUTPUT: «HeyHey»
但请注意,我们在 put
后面使用了括号。 没有这些括号,它将抛出异常(版本 6.d 及更高版本)。 如果在 for
之前以这种方式使用它,它也会引发异常;请改用方法形式 .put
。
.put for <1 2 3>; # OUTPUT: «123»
子例程 say§
multi say(** --> True)
打印给定对象的“要点”;如果对象是 Str
的子类,它将始终调用 .gist
。 与 put
相同,只是它使用 .gist
方法来获取对象的字符串表示;与 put
一样,它也会对 Junction
进行自动线程化。
注意:一些对象的 .gist
方法,例如 列表,只返回有关对象的部分信息(因此称为“要点”)。 如果你想打印文本信息,你很可能想使用 put
代替。
say Range; # OUTPUT: «(Range)»say ; # OUTPUT: «(Foo)»say 'I ♥ Raku'; # OUTPUT: «I ♥ Raku»say 1..Inf; # OUTPUT: «1..Inf»
例程 note§
method note(Mu: -->Bool)multi note( --> Bool)multi note(Str --> Bool)multi note(** --> Bool)
与 say
相似(因为它将调用打印对象的 .gist
方法),只是它将输出打印到 $*ERR
句柄(STDERR
)。 如果子例程形式没有给出任何参数,将使用字符串 "Noted"
。
note; # STDERR OUTPUT: «Noted»note 'foo'; # STDERR OUTPUT: «foo»note 1..*; # STDERR OUTPUT: «1..Inf»
此命令也会对 Junction
进行自动线程化,并且保证在对象是 Str
的子类时调用 gist
。
子例程 prompt§
multi prompt()multi prompt()
打印 $msg
到 $*OUT
句柄(如果提供了 $msg
),然后从 $*IN
句柄 获取 一行输入。 默认情况下,这等效于将 $msg
打印到 STDOUT,从 STDIN 读取一行,删除尾随换行符,并返回结果字符串。 从 Rakudo 2018.08 开始,prompt
将为数值创建 同形异义词,等效于调用 val prompt
。
my = prompt "What's your name? ";say "Hi, $name! Nice to meet you!";my = prompt("Say your age (number)");my Int = ;my Str = ;
在上面的代码中,如果 $age
作为数字正确输入,它将被鸭子类型化为同形异义词 IntStr
。
子例程 open§
multi open(IO() , |args --> IO::Handle)
使用给定的 $path
创建 一个句柄,并调用 IO::Handle.open
,将任何剩余的参数传递给它。 请注意,IO::Path
类型提供了许多用于从文件读取和写入的方法,因此在许多常见情况下,你不需要直接 open
文件或处理 IO::Handle
类型。
my = open :w, '/tmp/some-file.txt';.say: 'I ♥ writing Raku code';.close;= open '/tmp/some-file.txt';print .readchars: 4;.seek: 7, SeekFromCurrent;say .readchars: 4;.close;# OUTPUT: «I ♥ Raku»
子例程 slurp§
multi slurp(IO::Handle = , |c)multi slurp(IO() , |c)
将整个文件的内容吸入 Str
(如果为 :bin
,则吸入 Buf
)。 接受 :bin
和 :enc
可选命名参数,与 open() 的含义相同;可能的编码与所有其他 IO
方法中的编码相同,并在 encoding
例程中列出。 如果文件不存在或是一个目录,该例程将 fail
。 如果没有参数,子例程 slurp
将对 $*ARGFILES
进行操作,在没有文件名的情况下,$*ARGFILES
默认值为 $*IN
。
# read entire file as (Unicode) Strmy = slurp "path/to/file";# read entire file as Latin1 Strmy = slurp "path/to/file", enc => "latin1";# read entire file as Bufmy = slurp "path/to/file", :bin;
sub spurt§
multi spurt(IO() , |c)
$path
可以是任何具有返回 IO::Path
对象的 IO 方法的对象。在 $path
上调用 IO::Path.spurt
,转发任何剩余的参数。
选项§
:enc
内容将写入的编码。
:append
布尔值,指示是否追加到(可能)已存在的文件。如果文件尚不存在,则会创建它。默认为 False
。
:createonly
布尔值,指示如果文件已存在是否失败。默认为 False
。
示例§
# write directly to a filespurt 'path/to/file', 'default text, directly written';# write directly with a non-Unicode encodingspurt 'path/to/latin1_file', 'latin1 text: äöüß', :enc<latin1>;spurt 'file-that-already-exists', 'some text'; # overwrite file's contents:spurt 'file-that-already-exists', ' new text', :append; # append to file's contents:say slurp 'file-that-already-exists'; # OUTPUT: «some text new text»# fail when writing to a pre-existing filespurt 'file-that-already-exists', 'new text', :createonly;# OUTPUT: «Failed to open file /home/camelia/file-that-already-exists: file already exists …»
multi spurt(IO() )
从 Rakudo 编译器的 2020.12 版本开始,也可以在不使用任何数据的情况下调用 spurt
子例程。这将创建空文件,或者截断给定路径下任何现有文件。
# create an empty file / truncate a filespurt 'path/to/file';
sub run§
sub run(* ($, *@),: = '-',: = '-',: = '-',Bool : = False,Bool : = True,Bool : = False,Str : = 'UTF-8',Str : = "\n",: = ,Hash() : = ,:,: = False--> Proc)
不涉及 shell 运行外部命令并返回 Proc
对象。默认情况下,外部命令将打印到标准输出和错误,并从标准输入读取。
run 'touch', '--', '*.txt'; # Create a file named “*.txt”run <rm -- *.txt>; # Another way to use run, using word quoting for the# arguments
如果要传递一些变量,您仍然可以使用 < >
,但尽量避免使用 « »
,因为它会在您忘记引用变量时进行单词拆分。
my = ‘--my arbitrary filename’;run ‘touch’, ‘--’, ; # RIGHTrun <touch -->, ; # RIGHTrun «touch -- "$file"»; # RIGHT but WRONG if you forget quotesrun «touch -- »; # WRONG; touches ‘--my’, ‘arbitrary’ and ‘filename’run ‘touch’, ; # WRONG; error from `touch`run «touch "$file"»; # WRONG; error from `touch`
请注意,对于许多程序,--
是必需的,以便区分命令行参数和 以连字符开头的文件名。
一个已下沉的 Proc
对象,用于一个 退出 不成功的进程将抛出异常。如果您希望忽略此类失败,只需在非下沉上下文中使用 run。
run 'false'; # SUNK! Will throwrun('false').so; # OK. Evaluates Proc in Bool context; no sinking
如果您希望捕获标准输出或错误,而不是直接打印它们,您可以使用 :out
或 :err
参数,这将使它们可以使用各自的方法:Proc.out
和 Proc.err
。
my = run 'echo', 'Raku is Great!', :out, :err;.out.slurp(:close).say; # OUTPUT: «Raku is Great!».err.slurp(:close).say; # OUTPUT: «»
您可以使用这些参数将它们重定向到文件句柄,从而创建一种管道。
my = open :w, '/tmp/cur-dir-ls-alt.txt';my = run "ls", "-alt", :out();# (The file will contain the output of the ls -alt command)
这些参数非常灵活,例如允许句柄重定向它们。有关更多详细信息,请参阅 Proc
和 Proc::Async
。
另请参阅 new
和 spawn
,以获取更多示例和所有参数的说明。
sub shell§
multi shell(, : = '-', : = '-', : = '-',Bool :, Bool : = True, Bool :,Str :, Str : = "\n", : = , :)
通过系统 shell 运行命令,系统 shell 在 Windows 中默认为 %*ENV<ComSpec> /c
,在其他情况下默认为 /bin/sh -c
。所有 shell 元字符都由 shell 解释,包括管道、重定向、环境变量替换等等。shell 转义是一个严重的安全性问题,会导致对不寻常的文件名产生混淆。如果您想安全,请使用 run。
返回值为 Proc 类型。
shell 'ls -lR | gzip -9 > ls-lR.gz';
有关更多详细信息,例如如何捕获输出,请参阅 Proc
。
routine unpolar§
method unpolar(Real )multi unpolar(Real , Real )
返回一个 Complex
,其坐标对应于以弧度为单位的角度,其幅度对应于对象值或 $mag
(如果用作 sub
)。
say 1.unpolar(⅓*pi);# OUTPUT: «0.5000000000000001+0.8660254037844386i»
routine printf§
multi printf(Cool , *)
根据格式生成输出。使用的格式是调用者(如果以方法形式调用)或第一个参数(如果以例程形式调用)。其余参数将按照格式约定在格式中进行替换。有关可接受的格式指令的详细信息,请参阅 sprintf。
"%s is %s".printf("þor", "mighty"); # OUTPUT: «þor is mighty»printf( "%s is %s", "þor", "mighty"); # OUTPUT: «þor is mighty»
在 Junction
上,它也会自动穿线,但没有保证的顺序。
printf( "%.2f ", ⅓ | ¼ | ¾ ); # OUTPUT: «0.33 0.25 0.75 »
routine sprintf§
multi sprintf(Cool , *)
根据如下所述的格式返回一个字符串。使用的格式是调用者(如果以方法形式调用)或第一个参数(如果以例程形式调用)。
sprintf( "%s the %d%s", "þor", 1, "st").put; # OUTPUT: «þor the 1st»sprintf( "%s is %s", "þor", "mighty").put; # OUTPUT: «þor is mighty»"%s's weight is %.2f %s".sprintf( "Mjölnir", 3.3392, "kg").put;# OUTPUT: «Mjölnir's weight is 3.34 kg»# OUTPUT: «Mjölnir's weight is 3.34 kg»
此函数与 C 库中的 sprintf
和 printf
函数基本相同。这两个函数唯一的区别是 sprintf
返回一个字符串,而 printf
函数写入文件句柄。sprintf
返回一个 Str
,而不是一个字面量。
$format
被扫描以查找 %
字符。任何 %
都引入一个格式标记。指令指导参数的使用(如果有)。当使用除 %
以外的指令时,它指示如何将传递的下一个参数格式化为要创建的字符串。参数索引也可以在格式标记中使用。它们采用 N$
的形式,并在下面详细解释。
$format
可以定义在单引号或双引号中。双引号的 $format
字符串在被扫描之前会被插值,任何插值后的值包含 %
字符的嵌入字符串都会导致异常。例如
my = "Ab-%x-42";my = "30";sprintf("Product $prod; cost: \$%d", ).put;# OUTPUT: «Your printf-style directives specify 2 arguments, but 1 argument was supplied»« in block <unit> at <unknown file> line 1»
在处理未知输入时,应避免使用此类语法,方法是将所有变量放入 *@args
数组中,并在 $format
中为每个变量设置一个 %
。如果需要在格式字符串中包含 $
符号(即使作为参数索引),请对其进行转义或使用单引号形式。例如,以下两种形式都可以正常工作,不会出错
sprintf("2 x \$20 = \$%d", 2*20).put; # OUTPUT: «2 x $20 = $40»sprintf('2 x $20 = $%d', 2*20).put; # OUTPUT: «2 x $20 = $40»
总之,除非需要非常特殊的东西,否则使用单引号格式字符串并且不在格式字符串中使用插值字符串,可以减少意外问题的发生。
指令§
% | 一个字面百分号 |
c | 具有给定代码点的字符 |
s | 一个字符串 |
d | 一个带符号整数,以十进制表示 |
u | 一个无符号整数,以十进制表示 |
o | 一个无符号整数,以八进制表示 |
x | 一个无符号整数,以十六进制表示 |
e | 一个浮点数,以科学计数法表示 |
f | 一个浮点数,以固定小数点表示 |
g | 一个浮点数,以 %e 或 %f 表示 |
X | 与 x 相似,但使用大写字母 |
E | 与 e 相似,但使用大写 "E" |
G | 与 g 相似,但使用大写 "E"(如果适用) |
b | 一个无符号整数,以二进制表示 |
兼容性
i | %d 的同义词 |
D | %ld 的同义词 |
U | %lu 的同义词 |
O | %lo 的同义词 |
F | %f 的同义词 |
修饰符§
修饰符会改变格式指令的含义,但基本上是无操作的(语义仍在确定中)。
h | 将整数解释为本机 "short"(通常为 int16) | |
NYI | l | 将整数解释为本机 "long"(通常为 int32 或 int64) |
NYI | ll | 将整数解释为本机 "long long"(通常为 int64) |
NYI | L | 将整数解释为本机 "long long"(通常为 uint64) |
NYI | q | 将整数解释为本机 "quads"(通常为 int64 或更大) |
在 %
和格式字母之间,可以指定几个额外的属性来控制格式的解释。按顺序,这些是
NYI 使用 '$' 符号的格式参数索引§
在指令之前使用显式格式参数索引(范围从 1 到 N 个参数),例如 %2$d
。默认情况下,sprintf
将格式化列表中下一个未使用的参数,但参数索引允许您按顺序使用参数(请注意,除非您转义 $
,否则需要使用单引号)
无索引:§
sprintf '%d %d', 12, 34; # OUTPUT: «12 34»sprintf '%d %d %d', 1, 2, 3; # OUTPUT: «1 2 3»
NYI 有索引:§
当我们对所有指令进行索引时,第一个示例按预期工作。
sprintf '%2$d %1$d', 12, 34; # OUTPUT: «34 12»
但请注意,在第二个示例中混合使用索引指令和非索引指令时的效果(小心你所要求的)。第二个非索引指令获取第一个参数,但它也在最后一个指令中被明确请求
sprintf '%3$d %d %1$d', 1, 2, 3; # OUTPUT: «3 1 1»
标志§
一个或多个
空格 | 在非负数前添加空格 |
+ | 在非负数前添加加号 |
- | 在字段内左对齐 |
0 | 使用前导零,而不是空格,进行必要的填充 |
# | 确保任何八进制数的前导为“0”,非零十六进制数前缀为“0x”或“0X”,非零二进制数前缀为“0b”或“0B” |
v | NYI 向量标志(仅与指令“d”一起使用),请参见下面的描述 |
例如
sprintf '<% d>', 12; # OUTPUT: «< 12>»sprintf '<% d>', 0; # OUTPUT: «< 0>"»sprintf '<% d>', -12; # OUTPUT: «<-12>»sprintf '<%+d>', 12; # OUTPUT: «<+12>»sprintf '<%+d>', 0; # OUTPUT: «<+0>"»sprintf '<%+d>', -12; # OUTPUT: «<-12>»sprintf '<%6s>', 12; # OUTPUT: «< 12>»sprintf '<%-6s>', 12; # OUTPUT: «<12 >»sprintf '<%06s>', 12; # OUTPUT: «<000012>»sprintf '<%#o>', 12; # OUTPUT: «<014>»sprintf '<%#x>', 12; # OUTPUT: «<0xc>»sprintf '<%#X>', 12; # OUTPUT: «<0XC>»sprintf '<%#b>', 12; # OUTPUT: «<0b1100>»sprintf '<%#B>', 12; # OUTPUT: «<0B1100>»
当空格和加号同时作为标志给出时,空格将被忽略
sprintf '<%+ d>', 12; # OUTPUT: «<+12>»sprintf '<% +d>', 12; # OUTPUT: «<+12>»
当在%o
转换中给出#
标志和精度时,将在开头添加必要的 0。如果数字的值为0
,并且精度为 0,则不会输出任何内容;精度为 0 或小于元素的实际数量将返回左侧为 0 的数字
say sprintf '<%#.5o>', 0o12; # OUTPUT: «<00012>»say sprintf '<%#.5o>', 0o12345; # OUTPUT: «<012345>»say sprintf '<%#.0o>', 0; # OUTPUT: «<>» zero precision and value 0# results in no output!say sprintf '<%#.0o>', 0o1 # OUTPUT: «<01>»
向量标志 'v'§
此特殊标志(v
,后跟指令d
)告诉 Raku 将提供的字符串解释为整数向量,每个字符对应一个整数(使用ord
例程进行转换为整数)。Raku 依次将格式应用于每个整数,然后使用分隔符(默认情况下为点'.'
)连接生成的字符串。这对于在任意字符串中显示字符的序数值很有用
NYI sprintf "%vd", "AB\x[100]"; # OUTPUT: «65.66.256»
您还可以通过使用带参数索引的星号显式指定要用于分隔符字符串的参数编号(例如,*2$v
);例如
NYI sprintf '%*4$vX %*4$vX %*4$vX', # 3 IPv6 addresses[1..3], ":";
宽度(最小)§
参数通常默认情况下格式化为仅显示给定值所需的宽度。您可以通过在此处放置一个数字来指定一个最小宽度,该宽度可以覆盖默认宽度,或者从下一个参数(使用*
)或从指定参数(例如,使用*2$
)获取所需的宽度
sprintf "<%s>", "a"; # OUTPUT: «<a>»sprintf "<%6s>", "a"; # OUTPUT: «< a>»sprintf "<%*s>", 6, "a"; # OUTPUT: «< a>»NYI sprintf '<%*2$s>', "a", 6; # OUTPUT: «< a>»sprintf "<%2s>", "long"; # OUTPUT: «<long>» (does not truncate)
在所有情况下,指定的宽度将根据需要增加以适应给定的整数数值或字符串。如果通过*
获得的字段宽度为负数,则它与-
标志具有相同的效果:左对齐。
精度或最大宽度§
您可以通过指定一个.
后跟一个数字来指定精度(对于数字转换)或最大宽度(对于字符串转换)。对于浮点格式,除了g
和G
之外,这指定了小数点右侧显示多少位(默认值为 6)。例如
# These examples are subject to system-specific variation.sprintf '<%f>', 1; # OUTPUT: «"<1.000000>"»sprintf '<%.1f>', 1; # OUTPUT: «"<1.0>"»sprintf '<%.0f>', 1; # OUTPUT: «"<1>"»sprintf '<%e>', 10; # OUTPUT: «"<1.000000e+01>"»sprintf '<%.1e>', 10; # OUTPUT: «"<1.0e+01>"»
对于“g”和“G”,这指定了要显示的最大位数,包括小数点之前的位数和小数点之后的位数;例如
# These examples are subject to system-specific variation.sprintf '<%g>', 1; # OUTPUT: «<1>»sprintf '<%.10g>', 1; # OUTPUT: «<1>»sprintf '<%g>', 100; # OUTPUT: «<100>»sprintf '<%.1g>', 100; # OUTPUT: «<1e+02>»sprintf '<%.2g>', 100.01; # OUTPUT: «<1e+02>»sprintf '<%.5g>', 100.01; # OUTPUT: «<100.01>»sprintf '<%.4g>', 100.01; # OUTPUT: «<100>»
对于整数转换,指定精度意味着数字本身的输出应填充到此宽度(其中0
标志被忽略)
(请注意,此功能目前适用于无符号整数转换,但不适用于有符号整数。)
sprintf '<%.6d>', 1; # OUTPUT: «<000001>»NYI sprintf '<%+.6d>', 1; # OUTPUT: «<+000001>»NYI sprintf '<%-10.6d>', 1; # OUTPUT: «<000001 >»sprintf '<%10.6d>', 1; # OUTPUT: «< 000001>»NYI sprintf '<%010.6d>', 1; # OUTPUT: «< 000001>»NYI sprintf '<%+10.6d>', 1; # OUTPUT: «< +000001>»sprintf '<%.6x>', 1; # OUTPUT: «<000001>»sprintf '<%#.6x>', 1; # OUTPUT: «<0x000001>»sprintf '<%-10.6x>', 1; # OUTPUT: «<000001 >»sprintf '<%10.6x>', 1; # OUTPUT: «< 000001>»sprintf '<%010.6x>', 1; # OUTPUT: «< 000001>»sprintf '<%#10.6x>', 1; # OUTPUT: «< 0x000001>»
对于字符串转换,指定精度会截断字符串以适合指定的宽度
sprintf '<%.5s>', "truncated"; # OUTPUT: «<trunc>»sprintf '<%10.5s>', "truncated"; # OUTPUT: «< trunc>»
您还可以使用.*
从下一个参数获取精度,或从指定参数(例如,使用.*2$
)获取精度
sprintf '<%.6x>', 1; # OUTPUT: «<000001>»sprintf '<%.*x>', 6, 1; # OUTPUT: «<000001>»NYI sprintf '<%.*2$x>', 1, 6; # OUTPUT: «<000001>»NYI sprintf '<%6.*2$x>', 1, 4; # OUTPUT: «< 0001>»
如果通过*
获得的精度为负数,则它被视为没有精度
sprintf '<%.*s>', 7, "string"; # OUTPUT: «<string>»sprintf '<%.*s>', 3, "string"; # OUTPUT: «<str>»sprintf '<%.*s>', 0, "string"; # OUTPUT: «<>»sprintf '<%.*s>', -1, "string"; # OUTPUT: «<string>»sprintf '<%.*d>', 1, 0; # OUTPUT: «<0>»sprintf '<%.*d>', 0, 0; # OUTPUT: «<>»sprintf '<%.*d>', -1, 0; # OUTPUT: «<0>»
大小§
对于数字转换,您可以使用l
、h
、V
、q
、L
或ll
指定解释数字的大小。对于整数转换(d
u
o
x
X
b
i
D
U
O
),数字通常被假定为平台上的默认整数大小(通常为 32 或 64 位),但您可以覆盖它以改为使用标准 C 类型之一,如用于构建 Raku 的编译器支持的那样
(注意:以下内容均未实现。)
hh | 将整数解释为 C 类型“char”或“unsigned char” |
h | 将整数解释为 C 类型“short”或“unsigned short” |
j | 将整数解释为 C 类型“intmax_t”,仅与 C99 编译器一起使用(不可移植) |
l | 将整数解释为 C 类型“long”或“unsigned long” |
q、L 或 ll | 将整数解释为 C 类型“long long”、“unsigned long long”或“quad”(通常为 64 位整数) |
t | 将整数解释为 C 类型“ptrdiff_t” |
z | 将整数解释为 C 类型“size_t” |
参数顺序§
通常,sprintf
将下一个未使用的参数作为每个格式说明符要格式化的值。如果格式说明符使用 *
来要求额外的参数,这些参数将从参数列表中按它们在格式说明符中出现的顺序消耗,在要格式化的值之前。当参数由显式索引指定时,这不会影响参数的正常顺序,即使显式指定的索引将是下一个参数。
所以
my = 5; my = 2; my = 'net';sprintf "<%*.*s>", , , ; # OUTPUT: «< ne>»
使用 $a
作为宽度,$b
作为精度,$c
作为要格式化的值;而
NYI sprintf '<%*1$.*s>', , ;
将使用 $a
作为宽度和精度,$b
作为要格式化的值。
以下是一些更多示例;请注意,在使用显式索引时,如果格式字符串是双引号,则需要转义 $
sprintf "%2\$d %d\n", 12, 34; # OUTPUT: «34 12»sprintf "%2\$d %d %d\n", 12, 34; # OUTPUT: «34 12 34»sprintf "%3\$d %d %d\n", 12, 34, 56; # OUTPUT: «56 12 34»NYI sprintf "%2\$*3\$d %d\n", 12, 34, 3; # OUTPUT: « 34 12»NYI sprintf "%*1\$.*f\n", 4, 5, 10; # OUTPUT: «5.0000»
其他示例
NYI sprintf "%ld a big number", 4294967295;NYI sprintf "%%lld a bigger number", 4294967296;sprintf('%c', 97); # OUTPUT: «a»sprintf("%.2f", 1.969); # OUTPUT: «1.97»sprintf("%+.3f", 3.141592); # OUTPUT: «+3.142»sprintf('%2$d %1$d', 12, 34); # OUTPUT: «34 12»sprintf("%x", 255); # OUTPUT: «ff»
特殊情况:sprintf("<b>%s</b>\n", "Raku")
将不起作用,但以下方法之一将起作用
sprintf Q:b "<b>%s</b>\n", "Raku"; # OUTPUT: «<b>Raku</b>»sprintf "<b>\%s</b>\n", "Raku"; # OUTPUT: «<b>Raku</b>»sprintf "<b>%s\</b>\n", "Raku"; # OUTPUT: «<b>Raku</b>»
子例程 flat§
multi flat(**)multi flat(Iterable \a)
构造一个包含任何提供参数的列表,并返回在该列表或 Iterable
上调用 .flat
方法 (从 Any
继承) 的结果
say flat 1, (2, (3, 4), $(5, 6)); # OUTPUT: «(1 2 3 4 (5 6))»
例程 unique§
multi unique(+values, |c)
从调用者/参数列表中返回一个唯一值的序列,这样每个重复值的第一个出现都保留在结果列表中。unique
使用 === 运算符的语义来决定两个对象是否相同,除非指定了可选的 :with
参数以及另一个比较器。即使删除了重复项,也会保留原始列表的顺序。
示例
say <a a b b b c c>.unique; # OUTPUT: «(a b c)»say <a b b c c b a>.unique; # OUTPUT: «(a b c)»
(如果您知道输入已排序,使得相同的对象相邻,请使用 squish。)
可选的 :as
参数允许您在进行唯一化之前规范化/标准化元素。这些值将被转换以用于比较,但仍然是原始值出现在结果列表中;但是,只有第一个出现将显示在该列表中
示例
say <a A B b c b C>.unique(:as()) # OUTPUT: «(a B c)»
还可以使用可选的 :with
参数指定比较器。例如,如果想要一个唯一哈希列表,可以使用 eqv
比较器。
示例
my = %(a => 42), %(b => 13), %(a => 42);say .unique(:with(&[eqv])) # OUTPUT: «({a => 42} {b => 13})»
注意:由于 :with
Callable
必须与列表中的所有项目一起尝试,这使得 unique
遵循具有更高算法复杂度的路径。只要有可能,您应该尝试使用 :as
参数。
例程 repeated§
multi repeated(+values, |c)
这将从调用者/参数列表中返回一个重复值的序列。它接受与 unique 相同的参数,但不是在第一次看到元素时就传递它们,而是在第二次(或更多次)看到它们时才传递它们。
示例
say <a a b b b c c>.repeated; # OUTPUT: «(a b b c)»say <a b b c c b a>.repeated; # OUTPUT: «(b c b a)»say <a A B b c b C>.repeated(:as()); # OUTPUT: «(A b b C)»my = %(a => 42), %(b => 13), %(a => 42);say .repeated(:with(&[eqv])) # OUTPUT: «({a => 42})»
与 unique
一样,关联参数 :as
接受一个 Callable,它在比较之前规范化元素,:with
接受将要使用的相等比较函数。
例程 squish§
sub squish( +values, |c)
从调用者/参数列表中返回一个值的序列,其中一个或多个值的运行被替换为第一个实例。与 unique
一样,squish
使用 === 运算符的语义来决定两个对象是否相同。与 unique
不同,此函数只删除相邻的重复项;更远的相同值仍然保留。即使删除了重复项,也会保留原始列表的顺序。
示例
say <a a b b b c c>.squish; # OUTPUT: «(a b c)»say <a b b c c b a>.squish; # OUTPUT: «(a b c b a)»
可选的 :as
参数,就像 unique
一样,允许在比较之前临时转换值。
可选的 :with
参数用于设置适当的比较运算符。
say [42, "42"].squish; # OUTPUT: «(42 42)»# Note that the second item in the result is still Strsay [42, "42"].squish(with => :<eq>); # OUTPUT: «(42)»# The resulting item is Int
sub emit§
sub emit(\value --> Nil)
如果在任何供应或反应块之外使用,则会抛出异常 emit without supply or react
。在 Supply
块中,它将向流添加一条消息。
my = supply.tap( -> );
另请参阅 emit
方法的页面。
sub undefine§
multi undefine(Mu \x)multi undefine(Array \x)multi undefine(Hash \x)
已弃用 在 6.d 语言版本中,将在 6.e 中删除。对于 Array
和 Hash
,它将等效于分配 Empty
;对于其他所有内容,等效于分配 Nil
或在数组或哈希的情况下分配 Empty
,建议使用这些方法。
数组操作§
操作数组和其他可变集合的例程。
sub pop§
multi pop() is raw
在 Positional
参数上调用方法 pop
。该方法应该删除并返回最后一个元素,或者返回一个包装了 X::Cannot::Empty
的 Failure
,如果集合为空。
有关示例,请参阅 Array
方法 的文档。
sub shift§
multi shift() is raw
在 Positional
参数上调用方法 shift
。该方法在实际实现它的可变集合(例如 Array
或 Buf
)上,应该删除并返回第一个元素,或者如果集合为空,则返回 Failure
。
示例
say shift [1,2]; # OUTPUT: «1»
my of Int = [1];say shift ; # OUTPUT: «1»say shift ; # ERROR: «Cannot shift from an empty Array[Int]»
sub push§
multi push(\a, ** is raw)multi push(\a, \b)
在第一个参数上调用方法 push
,传递剩余的参数。方法 push
应该将提供的值添加到集合或其部分的末尾。有关此子例程的间接可能很有用的示例,请参阅 Hash
方法 的文档。
push
方法应该展平所有类型为 Slip
的参数。因此,如果您想为新的集合类型实现符合规范的方法,它应该表现得好像它的签名只是
multi method push(::?CLASS: ** is raw --> ::?CLASS)
如果新的类型实现了 Positional
角色,则 默认基类提供 对新类型实例的自动创建。如果新的类型不是 Positional
,则可以通过添加具有类似签名的多方法来支持自动创建
multi method push(::?CLASS: ** is raw --> ::?CLASS)
sub append§
multi append(\a, ** is raw)multi append(\a, \b)
在第一个参数上调用方法 append
,传递剩余的参数。方法 append
应该将提供的值添加到集合或其部分的末尾。与方法 push
不同,方法 append
应该遵循 单参数规则。因此,如果您想为新的集合类型实现符合规范的方法 append
,它应该表现得好像它的签名只是
multi method append(::?CLASS: +values --> ::?CLASS)
类似于 例程 push
,如果您想支持自动创建,您可能需要添加一个多方法
multi method append(::?CLASS: +values --> ::?CLASS)
append
的子例程形式在追加到 Hash
的值时很有用。而 方法 append
会静默地忽略被解释为命名参数的文字对,子例程会抛出
my = i => 0;append , i => (1, 42);CATCH ;# OUTPUT: «Unexpected named argument 'i' passed»
控制例程§
改变程序流程的例程,可能返回一个值。
sub exit§
multi exit()multi exit(Int(Any) )
使用返回码 $status
退出当前进程,如果没有指定值则退出码为零。退出值 ($status
),当它不为零时,需要由捕获它的进程(例如,一个 shell)适当地评估;这是从 Main 返回非零退出码的唯一方法。
exit
会阻止 LEAVE 阶段执行,但它会运行 &*EXIT
变量中的代码。
exit
应该只用作最后的手段,用来向父进程发出非零退出码的信号,而不是用来异常终止方法或子程序:请使用 异常 代替。
进程中第一次调用 exit
会设置返回码,无论在同一线程或任何其他线程中随后调用 exit
多少次。
sub done§
sub done(--> Nil)
如果在任何供应或反应块之外使用,则会抛出异常 done without supply or react
。在 Supply
块中,它将指示供应将不再发出任何内容。另请参阅 方法 done
的文档。
my = supply.tap( -> , done => );# OUTPUT: «Second : 1Second : 2Second : 3No More»
当在 supply
块中调用 done
时,传递给 done
命名的参数的块将被运行。
从 Rakudo 编译器的 2021.06 版本开始,也可以使用 done
提供值。
sub done( --> Nil)
指定的值将首先被 emit
,然后调用无参数的 done
。
my = supply.tap: -> , done =># OUTPUT: OUTPUT: «Val: 1Val: 2Val: 3Val: 42No More»
sub lastcall§
sub lastcall(--> True)
截断当前调度链,这意味着对 nextsame
、callsame
、nextwith
和 callwith
的任何调用都将找不到任何下一个候选者。请注意,由于 samewith
从头开始重新启动调度,因此不受 lastcall
截断当前链的影响。
考虑下面的例子。foo(6)
在 lastcall
未被调用时使用 nextsame
,因此它到达了 Any
候选者。foo(2)
也调用了 nextsame
,但由于 lastcall
首先被调用,调度链被截断,因此没有到达 Any
候选者。最后一个调用 foo(1)
也调用了 lastcall
,但是,它随后使用了 samewith
,不受其影响,因此调度从头开始重新启动,使用新的参数 6
命中了 Int
候选者,然后通过 nextsame
(不受之前调用 samewith
之前使用的 lastcall
影响) 继续到 Any
候选者。
multi foo (Int )multi foo (Any )foo 6; say '----';foo 2; say '----';foo 1;# OUTPUT:# Int: 6# Any 6# ----# Int: 2# ----# Int: 1# Int: 6# Any 6