第一章. 介绍

Introduction

声明

本章翻译仅用于 Raku 学习和研究, 请支持电子版或纸质版

第一章. 介绍

本章是该语言的全貌图; 如果你还不了解正在发生的一切,请不要担心。担心如果你到了本书的最后,你仍然没有了解全部!有讲很多东西,所以将围绕一些话题,重新审视其他话题,并通过一些练习看看它们是如何融合在一起的 - 这真的都是关于实践的。

为什么是 Raku?

对于初学者,你要学习 Raku。你也可能通过使用这种语言来使得物有所值!

但是什么使这种语言变得有吸引力? Perl 家族一直喜欢 DWIM-Do What I Mean。你经常做的事情应该很容易做,而最困难的事情应该是可能的。任何编程语言的用处都可以通过它解决问题的程度来衡量。

Raku 是一种出色的文本处理语言 - 甚至可能比 Perl 5 更好。正则表达式(第15章)有许多令人兴奋的新功能,可以更容易地匹配和提取文本。内置 grammar(第17章)功能允许你轻松编写复杂的规则来处理和响应文本。

渐进类型(第3章)允许你注释变量,并限制你可以存储的内容。例如,你可以指定数字必须是整数,正数或两个其他数字之间的数。你不必必须使用它(这是渐进的部分)。你将能够注释子例程接受什么以及它应该返回什么。这可以快速揭示数据边界的错误。

内置并发(第18章)功能允许你将问题分解为单独运行并可能同时运行的部分。该语言为你处理大部分内容。

惰性列表和无限列表允许你处理序列而无需过多复制或甚至一次拥有整个列表(第6章)。你可以轻松创建自己的无限惰性列表。

我可以继续前进,但是当你按照本书的方式工作时,你会遇到更多令人惊叹的功能。

有时你不想使用 Raku。没有语言能适用所有的工作。如果你更喜欢其他更好的东西,或者可以使用不同的工具更快地完成任务,那么对你来说更强大!但是,我希望本书可以帮助你在 Raku 中快速有效地完成你需要做的事情。

First Steps with the REPL

REPL 是一个 Read-Evaluate-Print-Loop 的工具,提供交互式提示。 REPL 计算你键入的代码,显示结果,然后再次提示你。这是尝试代码片段的快速方法。当你运行不带参数的 raku 时,它会启动它的 REPL:

% raku
To exit type 'exit' or '^D'
>

> 是等待你输入内容的提示。当你键入 Return 时,REPL 开始工作。通过使两个数字相加来尝试 REPL:

% raku
> 2 + 2
4

如果出现错误,它会让你知道并再次提示你:

% raku
> 2 + Hamadryas
===SORRY!=== Error while compiling:
Undeclared name:
    Hamadryas used at line 1
>

你还不知道为什么这失败,因为你刚开始读本书。这真的不重要,只要你知道 REPL 捕获错误并为你提供新提示就好了。如果你需要纠正错误,你应该能够使用向上箭头返回到上一行(或更远)来编辑和重新运行某些内容。

在继续之前,你应该了解一些其他技巧,这些技巧可以帮助你了解该语言的轮廓。

注意

当我在本书中编写方法时,我通常会在方法调用点号前面加上它,因此你知道它们是方法,就像在 .is-prime 中一样。点号不是名称的一部分。

方法是用于对象的预定义行为的标签。每个对象都有一个类型,而 .^name 方法告诉你它的类型:

% raku
> 3.^name
Int

对于整数,字面量 3Int 类型的对象。一旦你知道类型是什么东西,你可以阅读其文档,以找出你可以用它做什么。

行为定义在类中(第12章),这些类可以通过继承基于更通用的类。你可以使用 .^mro 方法查看继承链(尽管文档也告诉你了):

% raku
> 3.^mro
((Int) (Cool) (Any) (Mu))

对象可以执行从其继承的所有类的所有行为。这表明 3 是一个 Int,然后它是一个 Cool(方便的面向对象循环),然后它是一个 Any(几乎所有东西的基类),最后是一个 Mu(一个不是东西的东西 - 好好想一想!)。

使用 .^methods 查看对象的方法列表:

% raku
> 3.^methods
(Int Num Rat FatRat abs Bridge chr sqrt base
polymod expmod is-prime floor ceiling round
...)

该类型也是一个对象(一个类型对象)。这是没有具体值的东西的抽象表达。它也有方法:

% raku
> Int.^methods
(Int Num Rat FatRat abs Bridge chr sqrt base
polymod expmod is-prime floor ceiling round
...)

但是,你无法在类型对象上调用许多这样的方法。你会收到错误,因为还没有值:

% raku
> Int.sqrt
Invocant of method 'sqrt' must be an object instance of
type 'Int', not a type object of type 'Int'.

方法 .^name, .^mro.^methods 来自语言的元编程基础。考虑到文章的篇幅,这对于本书有点高级,所以你不会在这里阅读更多相关内容。

阅读文档

现在你已了解 REPL 以及如何查找对象的类型,你可能希望阅读文档中的那些内容。 p6doc 程序可以做到:

% p6doc Int
... lots of text

如果你想了解某种方法,可以将其添加到该类型中:

% p6doc Int.polymod
      method polymod

Defined as:
    method polymod(Int:D: +@mods)

Usage:
    INTEGER.polymod(LIST)
...

有时你找不到你期望的文档。当发生这种情况时,尝试继承的类之一:

% p6doc Int.sqrt
No documentation found for method 'sqrt'

% p6doc Cool.sqrt
  routine sqrt

Defined as:
    sub sqrt(Numeric(Cool) $x)
    method sqrt()

...

我发现自己主要在 https://docs.raku.org 阅读在线文档。比这更糟糕的是谷歌像“raku Int” 这样的东西,并跟踪第一个结果。该网站还有一个方便的搜索功能以帮助你查找,而无需使用全文搜索。你可以在本地运行同一站点。在每个页面的底部查找这些详细信息。

基础语法

You often need to read code from the inside out, as you would a math formula, so that’s how I approach it here: starting from the very tiny and building up from there. This is a survey of the things you need to know and will read about in upcoming chapters. Don’t worry if you are a bit overwhelmed at this point. You’ll get used to these things as you practice.

你经常需要从里到外读取代码,就像你的数学公式一样,这就是我这本书里的方法:从非常小的开始,从那里开始构建。这是对你需要了解的内容的调查,并将在后续章节中阅读。如果你在这一点上有点不知所措,别担心。练习时你会习惯这些东西。

At the lowest level a program has terms. These are the building blocks that form everything else. Think of these as the nouns of the language. Here are some terms:

程序中最低级别的是项。这些是构成其他一切的基本构成要素。将这些视为语言的名词。下面是一些项:

2
e
π
'Hello'
$x
now

These include literal data, such as 2 and 'Hello'; variables, such as $x; and defined symbols, such as π. nowis a term that represents the current time as an Instant object.

A variable typically starts with a sigil—a special character that denotes something about that variable. The variable $x has the $ sigil. Don’t worry about those just yet, although you’ll see more later in this chapter.

这些包括文字数据,例如 2'Hello';变量,例如 $x ;和定义的符号,例如 πnow 是一个项,表示当前时间为 Instant 对象。

变量通常以sigil开头 - 一个表示该变量的特殊字符。变量 $x$ sigil。不要担心那些,尽管你会在本章后面看到更多内容。

Operators and Expressions

An expression is a combination of terms and operators that produce a new value. If the terms are the nouns, operators are the verbs that specify the action. They turn one or more terms into a new value. Operands are the values that an operator uses. A unary operator does something to a single operand:

表达式是产生新值的术语和运算符的组合。如果术语是名词,则运算符是指定动作的动词。他们将一个或多个术语转换为新值。操作数是操作员使用的值。一元运算符对单个操作数执行某些操作:

- 137           # negate 137 to make -137
+ '137'         # convert the string '137' to a number
$x++            # add 1 to the current value in $x

That # and the text following it is a comment (which you’ll see more about in a moment). It’s some text that the program ignores and is a convenient way for you to leave notes about your code. I’ll often use comments to reinforce a point or show the output of an expression.

A binary operator works on two operands. Normally these operators show up between the operands (infixed):

#和它后面的文字是一个评论(你稍后会看到更多)。这是程序忽略的一些文本,是你留下关于代码的注释的便捷方式。我经常使用注释来强化一个点或显示一个表达式的输出。

二元运算符适用于两个操作数。通常这些运算符出现在操作数之间(infixed):

2 + 2            # add two numbers
$object.method() # the . method call operator
$x = 137         # assign a value to a variable

A ternary operator, such as the conditional operator, ?? !!, has three operands:

三元运算符,例如条件运算符,?? !!,有三个操作数:

$some_value ?? 'Yes' !! 'No'    # choose one of two values

If the first thingy evaluates to True, it selects the second thingy. Otherwise it selects the third thingy. You’ll see more of these in Chapter 3.

如果第一个东西评估为True,它会选择第二个东西。否则它选择第三个东西。你将在第3章中看到更多这些内容。

BEFORE, AFTER, AND AROUND

Operators come in several varieties, with names that describe their position and the number of operands they expect. You’ll see these terms throughout the book. A prefix operator comes before its operand and usually takes only one operand. The increment operator is an example. It adds one to the number in $x:

运营商有多种类型,其名称描述了他们的位置和他们期望的操作数。你会在整本书中看到这些术语。前缀运算符位于其操作数之前,通常只需要一个操作数。增量运算符就是一个例子。它在$ x中添加一个数字:

++$x

A postfix operator comes after its operand. There are increment forms of this type as well:

后缀运算符位于其操作数之后。还有这种类型的增量形式:

$x++

A circumfix operator surrounds its operand. Examples include the parentheses and the double quote marks:

外围操作符包围其操作数。示例包括括号和双引号:

( 1, 2, 3 )
"Hello"

A postcircumfix operator surrounds its operand but comes after something else. A single-element access to an Array or a Hash surrounds the index and comes after the variable name. The [] and <> are the operators that come after the name but surround the key:

postcircumfix运算符包围其操作数,但是在其他内容之后。对数组或哈希的单元素访问包围索引并位于变量名称之后。 []和<>是名称后面但围绕键的运算符:

@array[0]
%hash<key>

Those terms are in the documentation. There are other ways you can arrange operators that don’t have standard terms, so I’ve fashioned my own that I don’t expect to use that much.

A precircumfix operator surrounds an operand and comes before other operands. The reduction operator (Chapter 6) surrounds an operator that it places between each of the items that follow it. This adds all the numbers without having to specify a + between every pair:

这些术语在文档中。还有其他方法可以安排没有标准术语的操作员,所以我自己设计了我不希望使用那么多的操作员。

precircumfix运算符包围操作数,并且位于其他操作数之前。缩减操作符(第6章)围绕操作员,操作员将其放置在跟随它的每个项目之间。这会添加所有数字而不必在每对之间指定+:

[+] 1, 2, 3

A circumfix infix operator surrounds an infix operator. The hyperoperators <<>> surround an operator and distribute that infix operator along the two lists (Chapter 6):

外接中缀运算符围绕中缀运算符。超级运算符« »围绕一个运算符并在两个列表中分配该中缀运算符(第6章):

(1, 2, 3) <<+>> (4, 5, 6)

There are other arrangements you might encounter in this book, but you can generally tell how they work by picking apart the name.

Operators are actually methods. Their names look a bit complicated because they start with the sort of operator they are and have the symbol in angle brackets:

你可能会在本书中遇到其他安排,但你通常可以通过挑选名称来了解它们的工作原理。

运算符实际上是方法。它们的名字看起来有点复杂,因为它们以它们的运算符开头,并在尖括号中有符号:

infix:<+>(1, 2)     # 3

my @array = 1, 2, 3
postcircumfix:<[ ]>( @array, 1 )

You won’t need these forms, but you should know that the operators figure out what to do based on the arguments.

你不需要这些表单,但你应该知道运算符根据参数确定要执行的操作。

PRECEDENCE

You can chain operations one after the other. Try this in the REPL:

你可以一个接一个地链接操作。在REPL中尝试这个:

1 + 2 + 3 + 4

The expression is evaluated in order of operator precedence and associativity. Precedence decides which operators go first and associativity figures out the order among operators of the same precedence (or even two of the same operator).

An operator’s precedence is relatively looser or tighter than other operators. With a chain of terms the tighter operator goes first. Multiplication (*) happens before addition (+), just like in high school algebra:

表达式按运算符优先级和关联性的顺序进行计算。优先级决定哪些运算符优先,关联性在相同优先级的运算符(或者甚至是同一运算符中的两个)之间确定顺序。

运营商的优先级比其他运营商相对宽松或紧凑。通过一系列术语,更严格的运营商成为第一。乘法(*)在加法(+)之前发生,就像在高中代数中一样:

2 + 3 * 4       # 14

If you don’t like the order you can change it with parentheses. Things inside parentheses are computed before things outside. Another way to say that is that parentheses have the highest precedence. Now the addition happens first:

如果你不喜欢订单,可以使用括号更改订单。括号内的东西是在外面的东西之前计算出来的。另一种说法是括号具有最高优先级。现在首先添加:

(2 + 3) * 4     # 20

If you have two operators of the same precedence then associativity decides the order of evaluation. Operators can be either left associative or right associative. The exponentiation operator is right associative, so the operation on the right happens first:

如果你有两个具有相同优先级的运算符,则关联性决定评估的顺序。运算符可以是左关联的,也可以是右关联的。取幂运算符是右关联的,因此右边的操作首先发生:

2 ** 3 ** 4     # 2.4178516392293e+24

It’s the same order as if you put explicit parentheses around the right two numbers:

它与在右边两个数字周围放置明确括号的顺序相同:

2 ** (3 ** 4)     # 2.4178516392293e+24

Use parentheses to make the left operation happen first:

使用括号使左操作首先发生:

(2 ** 3) ** 4     # 4096

Some operators can’t be combined and don’t have associativity. The range operator is one of the operators you can’t combine:

有些运营商无法合并,也没有相关性。范围运算符是你无法组合的运算符之一:

0 .. 5       # Range operator, nonassociative
0 .. 3 .. 5  # Illegal

Statements

A statement is a complete, standalone part of a program. An expression can be a statement but it can also be part of a statement. Here’s a statement using put to output a message. It adds a newline for you:

声明是程序的完整独立部分。表达式可以是语句,但也可以是语句的一部分。这是一个使用put来输出消息的语句。它为你添加了换行符:

put 'Hello Raku!'

You separate statements with a semicolon. Here are two statements; they are on separate lines but you still need a semicolon between them:

用分号分隔语句。这是两个陈述;它们在不同的行上但你仍然需要在它们之间加一个分号:

put 'Hello Raku!';
put 'The time is ', now;

You don’t need the ; unless another statement follows, but I tend to put a semicolon at the end of every statement because I know I’ll forget to add it when I add more code:

你不需要;除非有其他声明,但我倾向于在每个语句的末尾加上分号,因为我知道在添加更多代码时我会忘记添加它:

put 'Hello Raku!';
put 'The time is ', now;

Most whitespace is insignificant, which means you can use it how you like to format your program. These statements have a differently organized manner:

大多数空白都是无关紧要的,这意味着你可以按照自己喜欢的方式使用它来格式化程序。这些陈述的组织方式不同:

put
    'Hello Raku!'

; put 'The time is ',
now               ;

There are a few situations where whitespace matters, but you’ll read about that when you need to know about it.

在某些情况下,空白很重要,但是当你需要了解它时,你会读到这些内容。

Blocks

A block (Chapter 5) combines one or more statements into a single unit by surrounding them with a set of braces. Sometimes the block has a control keyword, such as loop, attached to it. This block continually evaluates its statements until you stop the program with Control-C. This is an infinite loop:

一个块(第5章)通过用一组括号围绕它们将一个或多个语句组合成一个单元。有时块会附加一个控制关键字,例如循环。在使用Control-C停止程序之前,此块会持续评估其语句。这是一个无限循环:

loop {
    state $count = 0;
    sleep 1;
    print $count, "\r";
    }

Each statement is separated by a semicolon and the last statement has a semicolon for good measure.

You don’t see a ; after the closing brace for that loop, but it’s implicitly there. A } followed by nothing more than whitespace until the end of the line implies a ;. If you have more stuff on the same line, though, you need a ; after the }:

每个语句用分号分隔,最后一个语句用分号表示。

你没有看到;在该循环的右括号之后,但它隐含在那里。 A}后面只有空格,直到行尾意味着;。但是,如果你在同一条线上有更多的东西,你需要一个;之后 }:

loop { ... }; put "Done";

The ... (yada yada) operator is the way you signal that there’s something there but you don’t care to say what it is at the moment. Use it when you intend to fill in the details later. I’ll use those to hide code to save space in examples. It compiles but gives you an error when you run it. You’ll see this used throughout the book to shorten examples to fit on the page.

A block creates a lexical scope. You can see what this scope is based on the position of the braces (hence, lexical). Things you define inside a scope only matter inside that scope and the deeper scopes it defines. This limits the effects of many things to exactly where you need them. The effects of variables and modules are limited to their lexical scope.

……(yada yada)操作员是你发出信号的方式,但是你不想在此刻说出它是什么。如果你打算稍后填写详细信息,请使用它。我将使用这些来隐藏代码以节省示例中的空间。它会编译,但在运行时会出错。你将在本书中看到这一点,以缩短示例以适应页面。

块创建词法范围。你可以看到这个范围基于大括号的位置(因此,词汇)。你在范围内定义的内容仅在该范围内以及它定义的更深范围内。这将许多事物的影响限制在你需要它们的确切位置。变量和模块的影响仅限于它们的词法范围。

Comments

Comments are a way to leave ourselves notes that the program doesn’t care about. The compiler mostly ignores these things. You can make a comment with a # when the compiler is expecting a new token. The compiler skips everything from that # to the end of the line. Here’s a mostly useless comment:

评论是一种让自己留下该程序不关心的注释的方法。编译器大多忽略了这些东西。当编译器期望新的令牌时,你可以使用#进行注释。编译器会跳过从#到行尾的所有内容。这是一个无用的评论:

put 'Hello Raku!'; # output a message

A better comment expounds on the purpose, not the effect, of the code. This type of little program is often used as a first exercise to check that everything is working. The comment can say that:

更好的评论阐述了代码的目的,而不是效果。这种类型的小程序通常用作检查一切正常的第一个练习。评论可以说:

put 'Hello Raku!'; # show that the program ran

An alternative is an embedded comment. Put your message inside the parentheses in #( )` somewhere in your statement (or even between statements):

另一种选择是嵌入式评论。将你的消息放在语句中某处(甚至语句之间)的#()`中的括号内:

put #`(Marketing asked for this) 'Hello Raku!';

This is a nice way to have multiline comments:

这是获得多行注释的好方法:

#`(
* show that the program ran
* need to add blockchain email AI feature
)
put  'Hello Raku!';

Since a closing parenthesis ends the comment, you can’t have one in your comment.

Both of those are fine for short comments. Sometimes you want to comment out several lines to prevent them from running. If you put the # at the beginning of a line you effectively remove that line from the program:

由于右括号结束了注释,因此你的注释中不能有注释。

这两个都适合简短的评论。有时你想要注释掉几行以防止它们运行。如果你把#放在一行的开头,你就可以从程序中删除该行:

loop {
    state $count = 0;
#   sleep 1;
    print $count, "\r";
    }

You might add another comment to remind yourself why that line is still in the code. Often programmers do this as they are debugging so they remember what was there before they started:

你可以添加另一条注释来提醒自己为什么该行仍在代码中。程序员通常会在调试时执行此操作,以便他们记住启动之前的内容:

loop {
    state $count = 0;
# Testing this for ticket 1234 (bug://1234)
# I think that the sleep slows the program down too much
#   sleep 1;
    print $count, "\r";
    }

Unspace

In most places Raku doesn’t care about whitespace, but there are some parts of the Raku syntax that don’t allow spaces. Space between the name of a subroutine and its opening parenthesis for an argument list changes the meaning:

在大多数地方,Raku并不关心空格,但Raku语法的某些部分不允许使用空格。子例程名称与参数列表的左括号之间的空格改变了含义:

my-sub 1, 2, 3;            # three arguments
my-sub( 1, 2, 3 );         # three arguments
my-sub ( 1, 2, 3 );        # one argument (a List)

In that last line there’s a space between my-sub and the (. That compiles and runs, but instead of three arguments the subroutine gets a single List argument (Chapter 6). You can unspace that space with a backslash. Any whitespace following the \ is basically invisible to the compiler:

在最后一行中,my-sub和(。)之间有一个空格编译并运行,但是子程序不是三个参数,而是获取单个List参数(第6章)。你可以用反斜杠取消空格。任何空格跟随\对编译器基本上是不可见的:

my-sub\ (1, 2, 3 );

You might want to do this to format code into columns to make it easier to read:

你可能希望这样做以将代码格式化为列以使其更易于阅读:

my-sub\            ( 2, 4, 8 );
my-much-longer-name( 1, 3, 7 );

Objects and Classes

Raku is a class-based object system. I’ll skip most of the theory of object-oriented programming (that could be a whole other book), but you should know that in these systems a class (Chapter 12) defines the abstract structure and behavior of an object. The object is a particular concrete version of that class.

Most of the data in Raku are objects, and each object knows what class defines it. Classes define methods, which are the behaviors of the object. Classes can inherit from another class to include its behavior, but they can also include roles that add behavior without inheritance. When you see class names in the digital version of this book the name should link to the online documentation for that class (for example, the Int class).

You create objects by calling a constructor method, often called .new (Chapter 12). You pass arguments to the method in parentheses after the method name:

Raku是一个基于类的对象系统。我将跳过面向对象编程的大部分理论(可能是另一本书),但你应该知道在这些系统中,一个类(第12章)定义了一个对象的抽象结构和行为。该对象是该类的特定具体版本。

Raku中的大多数数据都是对象,每个对象都知道哪个类定义了它。类定义方法,这是对象的行为。类可以从另一个类继承以包含其行为,但它们也可以包含添加行为而不继承的角色。当你在本书的数字版本中看到类名时,该名称应该链接到该类的在线文档(例如,Int类)。

你可以通过调用构造函数方法来创建对象,通常称为.new(第12章)。在方法名称后面的括号中将参数传递给方法:

my $fraction = Rat.new( 5, 4 );

There’s also a colon syntax for method arguments which relieves you from the burden of typing the closing parenthesis as long as there’s nothing more in the statement:

方法参数还有一个冒号语法,只要语句中没有其他内容,就可以减轻输入右括号的负担:

my $fraction = Rat.new: 5, 4;

Type objects represent the abstract idea of a class but aren’t objects. Sometimes they are useful as placeholders when you know what sort of object you want but you don’t know its value yet:

类型对象表示类的抽象概念,但不是对象。当你知道你想要什么样的对象但你还不知道它的价值时,有时候它们可以用作占位符:

my $fraction = Rat;

With gradual typing you can restrict variables to fit into a type. These are runtime checks, so you don’t know that it didn’t work until you try it:

通过逐步输入,你可以限制变量以适合类型。这些是运行时检查,所以在尝试之前你不知道它不起作用:

my Int $n;

Since you haven’t assigned a value to $n yet, it’s an Int type object. When you want to assign a value it must match that type:

由于尚未为$ n分配值,因此它是Int类型对象。如果要分配值,则必须与该类型匹配:

$n = 137;          # works because it's an integer
$n = 'Hamadryas';  # fails

Look through a class’s documentation to see what sorts of things its objects can do. In many of the exercises I’ll ask you to use a method that I haven’t shown you. This trains you to go to the docs, but also lets you learn things about seeing what’s out there. This saves some space in the book. Let’s try some of those now.

EXERCISE 1.1What type of object is 137? Compute its square root. Is it a prime number? You should be able to do each of these with a simple method.

查看类的文档,了解其对象可以执行的操作。在许多练习中,我会要求你使用我没有给你看的方法。这会训练你去看文档,但也可以让你学习看看那里有什么。这节省了书中的一些空间。我们现在试试吧。

练习1.1什么类型的对象是137?计算其平方根。它是素数吗?你应该能够使用一种简单的方法完成其中的每一项。

Variables

Raku has named values. They can be immutable, which means you can’t change the values once you set them. They can also be mutable, which means you can change the values. The mutable ones are commonly called variables, but they are also known as containers. A container holds a value and you can replace that value with another. You’ll read more about that in the next chapter. Despite the possibility that you can’t change the value, I’ll still call all of these “variables.”

A named value has an identifier—a fancy word for “name.” Names can include letters, digits, the underscore, the hyphen, and the apostrophe ('). You must start your name with a letter or digit. These are valid identifiers:

Raku具有命名值。它们可以是不可变的,这意味着一旦设置它们就无法更改它们。它们也可以是可变的,这意味着你可以更改值。可变的通常称为变量,但它们也称为容器。容器包含值,你可以将该值替换为另一个值。你将在下一章中阅读更多相关内容。尽管你无法更改该值,但我仍然会调用所有这些“变量”。

命名值具有标识符 - “名称”的奇特单词。名称可以包括字母,数字,下划线,连字符和撇号(')。你必须以字母或数字开头。这些是有效的标识符:

butterfly_name
butterfly-name
butterfly'name

The underscore, hyphen, or apostrophe can separate words to make them easier to read. Sometimes the underscore pattern is called snake case since the word separators crawl along the ground. The hyphen pattern is called kebab case (or sometimes lisp case).

Some people might feel more at home capitalizing the first letter of each word instead. This is known as camel case since it imitates the humps on a camel’s back. In this example there’s one hump, which is the best number of humps for a camel:

下划线,连字符或撇号可以分隔单词以使其更易于阅读。有时下划线模式称为蛇形,因为单词分隔符沿着地面爬行。连字符模式称为kebab案例(或有时称为lisp案例)。

有些人可能会觉得在家里更多地将每个单词的第一个字母大写。这被称为骆驼案,因为它模仿骆驼背上的驼峰。在这个例子中有一个驼峰,这是驼峰的最佳驼峰数:

butterflyName

There are some rules with - and '. You can’t have two - or ' characters in a row, and the character after either must be a letter (not a number). Also, you cannot start an identifier with these characters. None of these are valid:

有一些规则 - 和'。你不能连续两个 - 或’字符,并且后面的字符必须是字母(不是数字)。此外,你无法使用这些字符启动标识符。这些都不是有效的:

butterfly--name
butterfly''name
'butterfly
butterfly-1

A variable name combines a sigil with an identifier. The sigil is a character that gives some context to the identifier. A scalar is a single thingy. A scalar variable holds a single value and has a $ sigil. The $ looks similar to S, for scalar:

变量名称将sigil与标识符组合在一起。 sigil是一个为标识符提供一些上下文的字符。标量是一个单一的东西。标量变量包含单个值并具有$ sigil。对于标量,$看起来类似于S:

$butterfly_name

As you encounter the different types you’ll encounter the other sigils. The @ is for positionals (Chapter 6), the %is for associatives (Chapter 9), and the & is for callables (Chapter 11).

The first time you use a variable you must declare it. You do this so the compiler knows you definitely want to use that name and to avoid problems with misspelling variables. The my keyword declares the variable to be private to the current scope:

当你遇到不同的类型时,你会遇到其他的印记。 @代表位置(第6章),%代表关联(第9章),&是适用于callables(第11章)。

第一次使用变量时,必须声明它。你这样做是因为编译器知道你肯定想要使用该名称并避免拼写错误变量的问题。 my关键字将变量声明为当前范围的私有变量:

my $number;

The next time you use $number in that same scope you don’t need to declare it. You probably want to assign it a value. The = is the assignment operator:

下次在同一范围内使用$ number时,你不需要声明它。你可能想要为其分配值。 =是赋值运算符:

$number = 137;

You initialize a variable first time you assign a value to it. You can do this at the same time that you declare it:

首次为其赋值时初始化变量。你可以在声明它的同时执行此操作:

my $number = 137;

Since Raku already knows which variables you intend to use it knows when you misspell one:

由于Raku已经知道你打算使用哪些变量,因此它知道你拼错了一个:

$numbear = 137;

You get an error that’s often aware enough to guess what you meant:

你会得到一个经常意识到足以猜出你的意思的错误:

Variable '$numbear' is not declared. Did you mean '$number'?

Simple Output

To see what’s in a variable you can use (or “call”) the put routine. This outputs the value to standard output and adds a newline to the end:

要查看变量中的内容,你可以使用(或“调用”)put例程。这会将值输出到标准输出并在结尾添加换行符:

put $number;

If you use say it calls the .gist method for you. This often results in the same output, but some complicated objects may summarize or elide data to give you something easier to read. These two do the same thing:

如果你使用say它会为你调用.gist方法。这通常会产生相同的输出,但是一些复杂的对象可能会总结或删除数据,以便你更容易阅读。这两个做同样的事情:

say $number;
put $number.gist;

If you don’t want to add a newline you can use print:

如果你不想添加换行符,可以使用print:

print $number;

There are also method forms of each of these:

还有以下各种方法形式:

$number.put;
$number.say;
$number.print;

Lexical Scope

A variable is only visible in its lexical scope. If you define a variable inside braces you can’t use it outside the braces:

变量仅在其词法范围内可见。如果在大括号内定义变量,则不能在大括号外使用它:

{
my $number = 137;
}

$number = 5; # a compilation error

This is caught when you try to compile the program:

当你尝试编译程序时会捕获此信息:

Variable '$number' is not declared

A variable of the same name can exist in the outer scope and isn’t disturbed when the same name is reused in a deeper scope:

外部作用域中可以存在同名变量,并且在更深的作用域中重用相同名称时不会受到干扰:

my $number = 5;
put $number;

{
my $number = 137;
put $number;
}

put $number;

These are two different variables that happen to use the same name. The compiler can tell them apart based on where you declared them. The inner scope declaration “hides” the outer scope one, so the result is:

这是两个碰巧使用相同名称的不同变量。编译器可以根据你声明它们的位置区分它们。内部范围声明“隐藏”外部范围一,因此结果是:

5
137
5

Sometimes a named value doesn’t have a sigil. These sigilless variables don’t create containers, which means that you can’t change their values. This makes them handy for values you don’t want anyone to accidentally change. Prefix the identifier with a \:

有时命名值没有印记。这些无形变量不会创建容器,这意味着你无法更改其值。这使得它们非常便于你不希望任何人意外更改的值。使用\前缀标识符:

my \magic-number = 42;
magic-number.put;

These statements actually create terms, but since you declare them like variables it’s slightly easier to be a little wrong than pedantically correct.

这些语句实际上创建了术语,但是因为你将它们声明为变量,所以稍微容易出错而不是迂腐正确。

Predefined Variables

Raku defines several variables for you. These are prefixed with a sigil and then an additional character called a twigil. The combination of characters tells you something about the variable. Don’t worry about all the sorts of twigils that exist. Know that they do exist and that you can read about them at https://docs.raku.org/language/variabless

Raku为你定义了几个变量。这些是以印记为前缀,然后是一个名为twigil的附加角色。字符组合会告诉你有关变量的信息。不要担心存在的所有种类的树枝。知道它们确实存在,你可以在https://docs.raku.org/language/variables或p6doc上阅读它们:

% p6doc language/variables

The ? twigil marks values that the compiler sets as it does its work. These are compile-time variables. If you want to know the file the compiler is working on you can look in $?FILE. The $ is the sigil and the ? is the twigil:

的? twigil标记编译器在工作时设置的值。这些是编译时变量。如果你想知道编译器正在处理的文件,你可以查看$?FILE。 $是sigil和?是twigil:

put $?FILE;

The * twigil marks dynamic variables. These are looked up through the caller’s scope, but that’s not the important part for this section. Your program automatically sets these values. Some of them are about the environment of the program:

twigil标志着动态变量。这些是通过调用者的范围查找的,但这不是本节的重要部分。你的程序会自动设置这些值。其中一些是关于该计划的环境:

% raku
To exit type 'exit' or '^D'
> $*EXECUTABLE
"/Applications/Rakudo/bin/raku".IO
> $*PROGRAM
"interactive".IO
> $*USER
hamadryas
> $*CWD
"/Users/hamadryas".IO

Others provide information about your version of Raku. This information might be useful if you need to report an issue:

其他人提供有关你的Raku版本的信息。如果你需要报告问题,此信息可能很有用:

> $*PERL
Raku (6.c)
> $*VM
moar (2018.04)

There are other dynamic variables for the standard filehandles. Each program gets output, input, and error filehandles. The standard output (the default place where output goes) is in $*OUT and standard error is in $*ERR. These are IO::Handle objects and you can call .put on them to make output:

标准文件句柄还有其他动态变量。每个程序都获得输出,输入和错误文件句柄。标准输出(输出的默认位置)在$ * OUT中,标准错误在$ * ERR中。这些是IO :: Handle对象,你可以在它们上调用.put来进行输出:

$*OUT.put: 'Hello Hamadryas!';
$*ERR.put: 'Hello Hamadryas!';

EXERCISE 1.2What is the $*CWD variable? What’s its value on your system?

EXERCISE 1.2 $ * CWD变量是什么?它对你的系统有什么价值?

Making and Running a Program

It’s time you wrote a program. That’s just a plain-text file that contains your source code. You don’t need any special software to create these files. They must be plain text though; word processors insert extra stuff and the compiler won’t tolerate that.

The first line in the program is typically the shebang line. That’s a Unix thing that lets a text file pretend to be a program. When you “run” the text file the system sees that the first two characters are #!. It uses the rest of that line as the name of the program that will actually run the code. That’s the interpreter:

是时候写一个程序了。这只是一个包含源代码的纯文本文件。你不需要任何特殊软件来创建这些文件。但它们必须是纯文本;字处理器插入额外的东西,编译器不会容忍。

该计划的第一行通常是shebang线。这是一个让文本文件伪装成程序的Unix东西。当你“运行”文本文件时,系统会看到前两个字符是#!。它使用该行的其余部分作为实际运行代码的程序的名称。那是翻译:

#!/Applications/Rakudo/bin/raku

Your package (or custom installation) may have installed it somewhere else, in which case you’d use that path:

你的包(或自定义安装)可能已将其安装在其他位置,在这种情况下你将使用该路径:

#!/usr/local/bin/raku

Some people use env since that looks through your PATH to find the program:

有些人使用env,因为它通过你的PATH查找程序:

#!/bin/env raku

Windows doesn’t know about shebangs, but it’s a good idea to include the shebang anyway since useful programs tend to escape into the world (life will find a way). For the rest of the book I’ll leave off the shebang line just to save space.

The rest of your file is your program. Here’s a common one that tests that you’ve probably done everything right. If you can run this program you’ve probably installed everything correctly:

Windows不知道shebangs,但是最好包括shebang,因为有用的程序往往会逃到这个世界(生活会找到一种方式)。为了本书的其余部分,为了节省空间,我将离开shebang线。

你文件的其余部分是你的程序。这是一个常见的测试,你可能已经做好了一切。如果你可以运行这个程序,你可能已正确安装了一切:

put 'Hello World!';

Ensure your editor is set to encode your file as UTF-8. Save the file using any name that you like. raku doesn’t care about the name, although the docs suggest a .p6 or .pl6 extension.

Run your program from the command line:

确保你的编辑器设置为将文件编码为UTF-8。使用你喜欢的任何名称保存文件。 raku并不关心名称,尽管文档建议使用.p6或.pl6扩展名。

从命令行运行你的程序:

% raku hello-world.p6

When you do this raku first compiles the program. It sees all of your program text and parses it. That’s the compile time part of the process. If it finds no problem it then runs what it has already compiled.

If you want to check your program without running it you can use the -c switch. This is a syntax check:

当你这样做时raku首先编译程序。它会查看所有程序文本并对其进行解析。这是该过程的编译时间部分。如果它没有发现任何问题,则运行它已编译的内容。

如果要在不运行程序的情况下检查程序,可以使用-c开关。这是语法检查:

% raku -c hello-world.p6

Most errors at this point are syntax errors; you wrote a program that Raku couldn’t parse.

EXERCISE 1.3Create the “Hello World” program and get it to run. Use any tools you like for that.

此时的大多数错误都是语法错误;你写了一个Raku无法解析的程序。

练习1.3创建“Hello World”程序并让它运行。使用你喜欢的任何工具。

Summary

You’ve seen the basic structure of a program and how you build up a program from smaller elements. You wrote some very small programs. You have some insights into the documentation; you’ll get more practice with that throughout your programming career. Now the trick is to make slightly larger programs.

你已经了解了程序的基本结构以及如何从较小的元素构建程序。你写了一些很小的程序。你对文档有一些了解;在整个编程生涯中,你将获得更多练习。现在的诀窍是制作稍大的程序。

comments powered by Disqus