首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Assignment

在 Ruby 中,赋值使用=(等号)字符。本例将数字5分配给本地变量v

代码语言:javascript
复制
v = 5

如果变量先前未被引用,则赋值会创建一个局部变量。

局部变量名称

局部变量名称必须以小写的 US-ASCII 字母或设置了8位的字符开头。通常,本地变量与 US-ASCII 兼容,因为键入它们的键存在于所有键盘上。

(Ruby 程序必须使用 US-ASCII 兼容的字符集编写,在这种字符集中,如果设置了8位,则表示扩展字符,Ruby 允许本地变量包含这些字符。)

局部变量名称可能包含字母,数字,_(下划线或下划线)或第八位设置的字符。

局部变量范围

一旦分配了本地变量名称 - 对该范围其余部分的所有名称使用都被认为是局部变量。

这里是一个例子:

代码语言:javascript
复制
1.times do
  a = 1
  puts "local variables in the block: #{local_variables.join ", "}"
end

puts "no local variables outside the block" if local_variables.empty?

这打印:

代码语言:javascript
复制
local variables in the block: a
no local variables outside the block

由于该块创建一个新的作用域,因此它内部创建的任何局部变量都不会泄漏到周围的作用域。

外部范围中定义的变量显示在内部范围内:

代码语言:javascript
复制
a = 0

1.times do
  puts "local variables: #{local_variables.join ", "}"
end

这打印:

代码语言:javascript
复制
local variables: a

您可以通过;在块的参数中列出它们来将块中的变量与外部范围隔离。有关示例,请参阅调用方法文档中的块局部变量文档。

另请参阅内核#local_variables,但请注意,for循环不会像块一样创建新的范围。

局部变量和方法

在 Ruby 中,局部变量名称和方法名称几乎完全相同。如果你还没有分配到其中一个不明确的名字,ruby 会假设你想调用一个方法。一旦你分配了名字,ruby 会假设你想引用一个局部变量。

分析器遇到赋值时创建局部变量,而不是在赋值时发生:

代码语言:javascript
复制
a = 0 if false # does not assign to a

p local_variables # prints [:a]

p a # prints nil

方法与局部变量名称之间的相似性会导致代码混淆,例如:

代码语言:javascript
复制
def big_calculation
  42 # pretend this takes a long time
end

big_calculation = big_calculation()

现在任何引用都big_calculation被认为是局部变量,并且会被缓存。要调用该方法,请使用self.big_calculation

您可以通过使用上面显示的空参数括号强制进行方法调用,或者使用类似的明确接收方来强制执行方法调用self.。如果方法的可见性不公开,则使用明确的接收方可能会引发 NameError。

另一个通常令人困惑的情况是使用修饰符时if

代码语言:javascript
复制
p a if a = 0.zero?

而非打印的“真”,你收到一个 NameError,“未定义的局部变量或方法a'”. Since ruby parses the bareleft of the,如果first and has not yet seen an assignment to一个it assumes you wish to call a method. Ruby then sees the assignment to了`,并会假设你引用一个本地方法。

这种混淆来自表达的乱序执行。首先分配局部变量 - 然后尝试调用不存在的方法。

变量实例

实例变量在同一对象的所有方法中共享。

实例变量必须以@(“at” 符号或商业地址)开头。否则,实例变量名称将按照规则作为局部变量名称。由于实例变量以@第二个字符开头,可能是一个大写字母。

这是一个实例变量用法的例子:

代码语言:javascript
复制
class C
  def initialize(value)
    @instance_variable = value
  end

  def value
    @instance_variable
  end
end

object1 = C.new "some value"
object2 = C.new "other value"

p object1.value # prints "some value"
p object2.value # prints "other value"

未初始化的实例变量的值为nil。如果您在启用警告的情况下运行 Ruby,您将在访问未初始化的实例变量时收到警告。

value方法可以访问该方法设置的值initialize,但只能访问同一个对象。

类变量

类变量在类,它的子类和它的实例之间共享。

类变量必须以@@(两个 “at” 符号)开头。名称的其余部分遵循与实例变量相同的规则。

这里是一个例子:

代码语言:javascript
复制
class A
  @@class_variable = 0

  def value
    @@class_variable
  end

  def update
    @@class_variable = @@class_variable + 1
  end
end

class B < A
  def update
    @@class_variable = @@class_variable + 2
  end
end

a = A.new
b = B.new

puts "A value: #{a.value}"
puts "B value: #{b.value}"

这打印:

代码语言:javascript
复制
A value: 0
B value: 0

继续相同的例子,我们可以使用任何一个类中的对象进行更新,并且该值是共享的:

代码语言:javascript
复制
puts "update A"
a.update

puts "A value: #{a.value}"
puts "B value: #{b.value}"

puts "update B"
b.update

puts "A value: #{a.value}"
puts "B value: #{b.value}"

puts "update A"
a.update

puts "A value: #{a.value}"
puts "B value: #{b.value}"

这打印:

代码语言:javascript
复制
update A
A value: 1
B value: 1
update B
A value: 3
B value: 3
update A
A value: 4
B value: 4

访问未初始化的类变量将引发 NameError 异常。

请注意,类有实例变量,因为类是对象,所以尽量不要混淆类和实例变量。

全局变量

全局变量无处不在。

全局变量以$(美元符号)开头。名称的其余部分遵循与实例变量相同的规则。

这里是一个例子:

代码语言:javascript
复制
$global = 0

class C
  puts "in a class: #{$global}"

  def my_method
    puts "in a method: #{$global}"

    $global = $global + 1
    $other_global = 3
  end
end

C.new.my_method

puts "at top-level, $global: #{$global}, $other_global: #{$other_global}"

这打印:

代码语言:javascript
复制
in a class: 0
in a method: 0
at top-level, $global: 1, $other_global: 3

未初始化的全局变量的值为nil

Ruby 有一些特殊的全局变量,其取决于上下文的行为有所不同,例如正则表达式匹配变量或分配给它时有副作用。详细信息请参阅全局变量文档。

分配方法

您可以定义像分配一样的方法,例如:

代码语言:javascript
复制
class C
  def value=(value)
    @value = value
  end
end

c = C.new
c.value = 42

使用赋值方法可以让程序看起来更漂亮。当分配给实例变量时,大多数人使用 Module#attr_accessor:

代码语言:javascript
复制
class C
  attr_accessor :value
end

使用方法分配时,您必须始终有一个接收器。如果你没有接收器,Ruby假定你正在分配一个局部变量:

代码语言:javascript
复制
class C
  attr_accessor :value

  def my_method
    value = 42

    puts "local_variables: #{local_variables.join ", "}"
    puts "@value: #{@value.inspect}"
  end
end

C.new.my_method

这打印:

代码语言:javascript
复制
local_variables: value
@value: nil

要使用分配方法,您必须设置接收器:

代码语言:javascript
复制
class C
  attr_accessor :value

  def my_method
    self.value = 42

    puts "local_variables: #{local_variables.join ", "}"
    puts "@value: #{@value.inspect}"
  end
end

C.new.my_method

这打印:

代码语言:javascript
复制
local_variables:
@value: 42

缩写赋值

您可以混合几个操作员和任务。要将1添加到您可以编写的对象:

代码语言:javascript
复制
a = 1

a += 2

p a # prints 3

这相当于:

代码语言:javascript
复制
a = 1

a = a + 2

p a # prints 3

您可以使用以下运算符是这样的:+-*/%**&|^<<>>

还有||=&&=。如果值是nilfalse当后者进行赋值时,前者进行赋值,如果该值不是nilfalse

这里是一个例子:

代码语言:javascript
复制
a ||= 0
a &&= 1

p a # prints 1

注意,这两个运营商更像a || a = 0a = a || 0

隐式数组赋值

分配时可以通过列出多个值来隐式创建一个数组:

代码语言:javascript
复制
a = 1, 2, 3

p a # prints [1, 2, 3]

这隐含地创建一个数组。

您可以*在分配时使用或 “splat” 运算符或解压缩数组。这与多次分配类似:

代码语言:javascript
复制
a = *[1, 2, 3]

p a # prints [1, 2, 3]

您可以在任务右侧的任何地方摔打:

代码语言:javascript
复制
a = 1, *[2, 3]

p a # prints [1, 2, 3]

多重分配

您可以将右侧的多个值分配给多个变量:

代码语言:javascript
复制
a, b = 1, 2

p a: a, b: b # prints {:a=>1, :b=>2}

在下面的章节中,任何使用“变量”的地方都可以使用赋值方法,实例,类或全局:

代码语言:javascript
复制
def value=(value)
  p assigned: value
end

self.value, $global = 1, 2 # prints {:assigned=>1}

p $global # prints 2

您可以使用多个赋值就地交换两个值:

代码语言:javascript
复制
old_value = 1

new_value, old_value = old_value, 2

p new_value: new_value, old_value: old_value
# prints {:new_value=>1, :old_value=>2}

如果赋值右侧的值比左侧的变量多,则会忽略额外的值:

代码语言:javascript
复制
a, b = 1, 2, 3

p a: a, b: b # prints {:a=>1, :b=>2}

您可以使用*它在作业的右侧收集额外的值。

代码语言:javascript
复制
a, *b = 1, 2, 3

p a: a, b: b # prints {:a=>1, :b=>[2, 3]}

*可以在左侧的任意位置出现:

代码语言:javascript
复制
*a, b = 1, 2, 3

p a: a, b: b # prints {:a=>[1, 2], :b=>3}

但你只能*在任务中使用一个。

数组分解

像方法参数中的数组分解一样,您可以在使用括号进行赋值时分解数组:

代码语言:javascript
复制
(a, b) = [1, 2]

p a: a, b: b # prints {:a=>1, :b=>2}

您可以将数组分解为更大的多个赋值的一部分:

代码语言:javascript
复制
a, (b, c) = 1, [2, 3]

p a: a, b: b, c: c # prints {:a=>1, :b=>2, :c=>3}

由于每个分解都被认为是它自己的多重赋值,因此可以用它*来收集分解中的参数:

代码语言:javascript
复制
a, (b, *c), *d = 1, [2, 3, 4], 5, 6

p a: a, b: b, c: c, d: d
# prints {:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]}

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com