crystal-lang入门(二)

CONTROL FLOW

Primitive Types

Nil

最简单的类型就是Nil,它只有一个值,意味数值不存在。

是否还记得String#index 。它返回一个nil值如果子字符串不存在于检索的字符串。它没有index,所以index位置不存在。

 

 

 Bool

bool类型只有两个可能的值false和true。代表了布尔代数和逻辑真值。

布尔值对于管理程序中的控制流特别有用。

Boolean Algebra

下面这个例子展示了操作符根据布尔值执行布尔代数:

 
a = true
b = false

p! a && b, # conjunction (AND)
   a || b, # disjunction (OR)
   !a,     # negation (NOT)
   a != b, # inequivalence (XOR)
   a == b  # equivalence

Truthiness

布尔代数不限制类型仅为布尔类型。所有值有一个潜在真值:nil,false。以及null指针是falsey的,其他任一值(包括0)是truthy。

用"foo"和nil代替上例的true和false看看。

a = "foo"
b = nil

p! a && b, # conjunction (AND)
   a || b, # disjunction (OR)
   !a,     # negation (NOT)
   a != b, # inequivalence (XOR)
   a == b  # equivalence

AND和OR运算符返回与运算符真值匹配的第一个操作数。

 

 

 

p! "foo" && nil,
   "foo" && false,
   false || "foo",
   "bar" || "foo"

NOT, XOR,==总是返回一个布尔值 (truefalse)。

Control Flow

Conditionals

message = "Hello World"

if message.starts_with?("Hello")
  puts "Hello to you, too!"
end

条件子句把代码分支放在门后,这个门只符合条件才开放。

最基本的形式包含了关键词if,其后跟着一个表达式作为条件语句。条件语句当表达式的返回值是truthy时才满足。所有后续的表达式都是分支的一部分直到由关键词end结束。

按照惯例,我们将嵌套的分支缩进两个空格。

上例打印message仅当它满足条件语句,Hello在字符串开头。

从技术上讲,这个程序仍然以预定义的顺序运行。fixed message总是匹配并使条件为真。但是假设我们没有在源代码中定义message的值。它也可以来自用户输入,例如聊天客户端。

如果message 有一个值但不是以Hello开始,那么程序会跳过条件分支并不打印任何东西。

条件表达式可以更复杂。使用布尔代数,我们可以构造一个接受Hello或Hi的条件:

message = "Hello World"

if message.starts_with?("Hello") || message.starts_with?("Hi")
  puts "Hey there!"
end

让我们把条件转换一下,只打印message当字符串不是以Hello为开头。

这只是与上一个示例的一个小偏差:我们可以使用否定运算符(!)把条件变成相反的表达式

message = "Hello World"

if !message.starts_with?("Hello")
  puts "I didn't understand that."
end

另一种方法是将if替换为关键字unless,它期望相反的真值。unless x相当于 if !x。

message = "Hello World"

unless message.starts_with?("Hello")
  puts "I didn't understand that."
end

让我们看一个使用String#index查找子字符串并突出显示其位置的示例。还记得如果找不到子字符串,它返回nil吗?那样的话,我们什么都不能显示。所以我们需要一个if子句,条件是检查index是否为nil。.nil?方法是完美的。 

str = "Crystal is awesome"
index = str.index("aw")

if !index.nil?
  puts str
  puts "#{" " * index}^^"
end

 

 编译器实际上强制您处理nil情况。尝试删除条件或将条件更改为true:将显示一个类型错误,并说明不能在该表达式中使用Nil值。在适当的条件下,编译器知道在分支内index不能为nil,它可以用作数字输入。

if !index.nil?的缩写是if index,两者基本上是等价的。只有当您想区分一个falsy值是nil还是false时,才有区别,因为前者的条件匹配false,而后者则不匹配。

Else

message = "Hello World"

if message.starts_with?("Hello")
  puts "Hello to you, too!"
end

if !message.starts_with?("Hello")
  puts "I didn't understand that."
end

让我们改进我们的程序,并在这两种情况下做出反应,不管消息是否满足条件。
我们可以将其作为两个独立的条件,条件为否定:

message = "Hello World"

if message.starts_with?("Hello")
  puts "Hello to you, too!"
else
  puts "I didn't understand that."
end

这是可行的,但有两个缺点:条件表达式message.starts_with?(“Hello”)计算两次,效率很低。后来,如果我们在一个地方更改了条件(可能也允许Hi),我们可能也会忘记更改另一个。
条件函数可以有多个分支。另一个分支由关键字else表示。如果不满足条件,则执行。

More branches

我们的程序只对Hello做出反应,但我们需要更多的交互。让我们添加一个分支来响应Bye。我们可以在同一个条件中有不同条件的分支。它就像一个else和另一个合成的if。因此关键字是elsif:

else分支仍然只在前面两个条件都不满足时执行。不过,它总是可以省略的。

请注意,不同的分支是互斥的,条件从上到下求值。在上面的例子中,这并不重要,因为这两个条件不能同时为真(message不能以Hello和Bye开头)。但是,我们可以添加一个非独占的替代条件来证明这一点:

message = "Bye World"

if message.starts_with?("Hello")
  puts "Hello to you, too!"
elsif message.starts_with?("Bye")
  puts "See you later!"
else
  puts "I didn't understand that."
end

这两个从句的分支条件相同,但顺序不同,它们的行为也不同。第一个匹配条件选择执行哪个分支。

message = "Hello Crystal"

if message.starts_with?("Hello")
  puts "Hello to you, too!"
elsif message.includes?("Crystal")
  puts "Shine bright like a crystal."
end

if message.includes?("Crystal")
  puts "Shine bright like a crystal."
elsif message.starts_with?("Hello")
  puts "Hello to you, too!"
end

 

posted @ 2021-04-11 16:10  世界を変える御宅族  阅读(170)  评论(0编辑  收藏  举报