Raku 编程/类型和上下文
我们已经讨论了各种基本数据类型,例如标量、数组和哈希。每个变量的符号都会将其置于特定的上下文中。不同类型的变量在不同上下文中使用时会有不同的行为。至少有两种基本类型的上下文,我们现在要谈论其中两种:标量上下文和列表上下文。标量是带有 $ 符号的任何东西,而列表是像数组和哈希这样的东西。
我们现在要谈论 Raku 的一个内置函数:say
。say
在程序运行时将一行文本打印到控制台。这是我们将在后面详细讨论的更大的输入输出 (I/O) 系统的一部分。say
接收一个字符串或一个字符串列表,并将它们打印到控制台。
say "hello world!";
say "This is ", "Raku speaking!";
范围是具有某种数值关系的值列表。范围使用 ..
运算符创建
my @digits = 0..9; # (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
范围也可以使用变量作为分隔符
my $max = 15;
my $min = 12;
my @list = $min .. $max; # (12, 13, 14, 15);
范围是一种与数组完全不同的对象类型,即使范围会创建一个类似数组的值列表。范围实现了一种称为延迟求值的行为:范围不会首先计算所有值的列表,而是仅以开始和结束点进行紧凑存储。稍后,当实际从范围内读取值时,可以从范围中计算出值。这意味着我们可以轻松地拥有无限范围而不会占用所有计算机内存
my @range = 1..Inf; # Infinite range, finite memory use
my $x = @range[1000000]; # Calculated on demand
延迟求值不仅仅是范围的行为,它实际上直接内置在 Raku 中,并且在许多地方自动使用。这意味着大型数组不一定会占用大量内存,而是可以在需要时才计算值。
我们可以使用各种强制转换技术来指定数据项的上下文。$( )
强制将括号之间的任何内容都视为标量,即使它通常不是标量也是如此。@( )
和 %( )
对数组和哈希也是如此。由于 ~
始终与字符串相关联,而 +
始终与数字相关联,因此我们可以使用它们将值分别强制转换为字符串和数字
my Num $x = +"3"; # Becomes a number
my Str $y = ~3; # The string "3"
my $z = $(2..4); # Three elements, but still a single Range object
my @w = @("key" => "value"); # Convert hash to array
上面的示例并不是从一种类型强制转换为另一种类型的唯一情况。强制转换使我们能够将变量强制转换为特定类型。在某些情况下,复杂的变量类型或类在强制转换方式不同时可能会表现出非常不同的行为。我们将在后面的章节中讨论这些情况。
以下是一个快速列出的上下文说明符
+( )
- 转换为数字
~( )
- 转换为字符串
$( )
- 转换为标量
@( )
- 转换为数组
%( )
- 转换为哈希
我们之前讨论过 Raku 是一种动态语言,因此其中的变量和数据项没有预定义的类型。我们还提到了,几乎是在脚注中,Raku 也有一个类型系统,如果需要,可以可选地使用它。Raku 是一种非常灵活的语言,旨在为程序员提供很大的自由度,以便以不同的方式进行编程。Raku 提供给程序员的一种编程方式是结构化的、静态类型的编程。
如果为变量指定类型,Raku 将遵循该类型,并且只允许使用该类型的变量。这在某些情况下非常有用,因为某些操作类将引发编译时错误而不是运行时错误。此外,如果编译器知道变量类型永远不会改变,则可以自由地执行某些类型的优化。这些行为是与实现相关的,当然 - 只有在你尝试利用它们时才会有用。一般规则是,你提供给编译器的信息越多,编译器为你进行的分析就越有用。
我们之前还提到过,变量在使用之前不需要显式声明。这也是对真相的稍微夸大了。变量不需要事先声明,但 Raku 让你可以选择这样做。要预先声明变量,可以使用 my
关键字
my $x = 5;
my
将变量定义为局部词法变量。另一种方法是将其定义为 our
以使其成为全局共享变量。Raku 中全局变量的另一个名称是“包变量”,因为它可供整个软件包或文件使用。
our $x = 5;
全局变量很好,因为你可以在任何地方使用它们,而无需将它们传递来回并跟踪它们。但是,与幼儿园不同的是,在大型程序中,共享并不总是最好的主意。
Raku 提供了一些内置类型,Raku 编译器事先知道这些类型。你始终可以定义自己的类型,但 Raku 从一开始就提供了一些类型。以下是一些 Raku 内置基本类型的部分列表。这不是一个完整的列表,因为 Raku 中的一些类型在目前还无法理解。
- Bool
- 布尔值,真或假。布尔值是枚举类型,我们将在稍后更详细地讨论。布尔值只能是
True
或False
。 - Int
- 基本整数值
- Array
- 值数组,由整型下标索引
- Hash
- 由字符串索引的值哈希
- Num
- 浮点数
- Complex
- 类似于浮点数,但也允许虚数和复数数据类型。
- Pair
- 我们在讨论哈希时简要提到了对。对是数据对象和字符串的组合。
- Str
- 字符串数据对象
使用这些值,你可以像在正常的静态类型语言中一样编写静态类型代码
my Int $x;
$x = 5; # Good, it's an integer
$x = "five"; # Bad, just the name of an integer
我们也可以使用类型系统来捕获数据在变量之间移动时的错误
my Int $foo = 5;
my Num $bar = 3.14;
$foo = $bar; # ERROR! $bar is not an Int!
这样,编译器就可以告诉你是否试图以你没有预想的方式使用变量。