ESS多版本 【TA】【ESS】08 变量的作用域

TAAAAAAA

天王
管理成员
2024/06/16
273
4
38
1,270
8: More variables and scopes 变量的作用域

So far, we’ve been using normal variables such as the one you see in the example below.

到目前为止,我们所使用的变量都是一般变量,我们来看下面的这个例子:


Here, age is what’s called a local variable. Any variable that doesn’t start with an uppercase letter or a character like @, @@ or $, is always a local variable.

这里的age就是一个一般变量,这个一般变量实际上是一个局部变量。
局部变量,顾名思义,就只能在局部使用,也就是说,只能在某些特定的地方使用。

In a script, you have multiple scopes. A scope is essentially a range of code with its own collection of methods, local variables, accessibility, et cetera. As we touched upon with methods, a new method has a different scope than the “main” scope. This means that local variables in the main scope aren’t the same as local variables in the method’s scope, even if they have the exact same name.

这些特定的地方,其实就是作用域,之前我们也已经是说过了,不同的作用域并不互通,所以某一个作用域里面的局部变量,你并不能在另一个作用域里使用。
 

TAAAAAAA

天王
管理成员
2024/06/16
273
4
38
1,270
Constants 常量

While you can’t access local variables from different scopes, constants can help work around that. You can have constants in the main scope, or a class’ scope. What differentiates local variables from constants, is the uppercase letter all constants start with. Variable would be a constant, whereas variable would be a local variable.

虽然局部变量不能在不同的作用域之间被访问,但是常量却可以。
常量就是以大写字母开头的那些变量,也就是说,如果你写age,那么age就是一个局部变量,而如果你写Age,那么Age就是一个常量。

These constants are accessible from anywhere at any time, as seen in the example here.

常量可以在任何地方、任何时候被访问,我们来看下面的这个例子:


This works because the constants can be accessed from different scopes too. The Age constant is defined in the main scope, and is later accessed in the print_age method’s scope. If you were to try this with a local variable, it would raise an error, stating the variable doesn’t exist.

虽然Age是在主作用域被定义的,但是Age依然可以在print_age这个方法的作用域里被访问。

There’s one more difference aside from visibility/accessibility, which comes in when you try to change the value of the constant during run-time. A constant is initialized once, and isn’t meant to be changed after that.In most languages, this isn’t possible in the first place. In Ruby, however, the value does in fact change, but you’ll get a warning that the constant has already been defined before.

另外还有一点是,常量在Ruby中也是可以被改变的,但是,虽然可以,但不推荐你去改变一个常量的值。
 

TAAAAAAA

天王
管理成员
2024/06/16
273
4
38
1,270
Constants and classes 常量和类

Classes can also have constants within them. When you do, they’re treated kind of similar to class methods and the like. Constants aren’t a part of an instance of the class, but they exist on the class itself. To then reference the constant inside that class, you’ll first have to type the name of the class, followed by ::, followed by the constant name.

类里面可能会有一些常量。
我们可以和调用类方法一样,使用::访问常量,请看下面的这个例子:

The Age constant has been created not in the main scope this time, but in NewClass’s scope. This means that you can’t access it directly (which would be print Age), but that you have to go into the class’ scope first (NewClass::).

在这个例子中,即使Age是在NewClass类(新类类)中被定义的,我们依然可以在主作用域中通过NewClass::Age访问它。

You can also have a class in a class in a class, et cetera et cetera. When you then want to refer to a so-called subclass, you also type MainClass::SubClass to reference it. (A subclass is completely independent of the class it’s in; it just has a different scope, which means you always need to type MainClass::SubClass to use it (unless you’re in MainClass itself, in which case just SubClass suffices, because you’re already in the MainClass’s scope)).

在一个类中,可以嵌套另一个类,我们来看下面的例子:


(You can’t have a class and a constant with the same name in the same scope.)

注意,在同一个作用域内,你不能有同名的常量和类。
 

TAAAAAAA

天王
管理成员
2024/06/16
273
4
38
1,270
Instance variables 实例变量

As the name suggests, instance variables are variables bound to class instances and its scope. Whereas local variables exist in one scope only, instance variables are carried by the instance/object of the class. The difference between local variables and instance variables is that the latter always start with 1 ‘@’. Whether or not the letter after that is uppercase or lowercase doesn’t matter.

实例变量,顾名思义,就是专用于实例的变量。
实例变量用来存储实例的某一个属性,或者说状态,我们来看下面的这个例子:


If you were to try this with local variables (without the @), it would perform age = 10 in def initialize, but then that method ends and the variable is gone again. Then calling print_age would try to access a non-existent variable, because there’s no local variable defined in print_age called age.

在上面的例子中,如果你不使用实例变量,而是使用局部变量的话,也就是age = 10,那么在初始化方法结束之后,这个变量没有了,你无法在print_age中调用age。
你也可以用作用域来理解,初始化方法的作用域和print_age方法的作用域是独立不互通的,所以它们之间的局部变量不能互相访问,而实例变量就可以在同一个类中的不同方法之间直接访问。

This is solved by using instance variables. These variables exist as long as the object they’re in exists. We can’t directly access this variable from outside of the class though, nor on the object itself (var). You have to be in the class to manipulate instance variables. For this you need to create helper methods, methods that allow you to read and write to the variable from the outside. This is pretty basic:

实例变量虽然可以在同一个类中的不同方法之间直接访问,但是却不能在这个类之外直接进行访问,你只能在这个类之内操纵实例变量。
为了能在外部访问实例变量,我们需要创建一些辅助方法来帮助我们,请看下面的这个例子:


But that’s convoluted and annoying to do for every single instance variable (if it’s a big class, you can easily have dozens of instance variables). That’s why we can create getter and setter methods. Getter methods are basically just methods with the same name as the instance variable, which return the value of said instance variable (exactly the same as get_age but with a different name). Setters are a bit different though. Rather than set_age(10), setter methods allow you to use assignment with = to call the method (yes, assignment is also a method!)

但是,为每一个实例变量都添加这样的两个方法是非常烦人的。
所以我们创造了获取器和设置器方法。
获取器是一个和变量的名字相同的方法,而设置器是一个在变量的名字后面加一个“=”的名字的方法。
假如说有个实例变量是@age,那获取器就是age,设置器就是age=,注意,这个“=”是设置器名字的一部分。

First to demonstrate the getter method:

首先我们来看获取器的例子:


Next comes the setter method:

接着我们来看设置器的例子:


So when you create a method with an equal sign = at the end of the method name, that method will be treated as an assignment method, with =.

There’s really no need for getter and setter methods, unless you want the instance variable to BE public and to be used outside of the class itself.

These getter and setter methods can be very useful, but it’s a lot to write if you have a lot of instance variables. That’s why there are shortcuts for these getters and setters:

attr_reader: This is the getter method. Equal to def age in the previous examples.
attr_writer: This is the setter method. Equal to def age=(v) in the previous examples.
attr_accessor: This is both the getter and the setter method. Equal to def age and def age=(v) in the previous examples.

因为获取器和设置器实在是太基础也太重要了,所以我们又创造了更加简便的添加获取器和设置器的方法。
添加获取器,我们只需要写attr_reader(读取器),添加设置器,我们只需要写attr_writer(写入器),而如果你写attr_accessor(访问器)的话,就是同时添加了获取器和设置器。

attr also means Attribute. Attribute reader (getter), Attribute writer (setter), Attribute accessor (getter + setter).

这里的“attr”其实是attribute(属性)的简写,attr_reader就是属性的读取器,attr_writer就是属性的写入器,attr_accessor就是属性的访问器,即读取器+写入器。

To use these shortcuts, you choose the keyword followed by a colon :, followed by the name of the instance variable. When used, it will basically turn into the proper method(s) in the order you wrote them. This means that you can overwrite the functionality later, if you want, just by typing out the method and implementing your desired functionality (just like a normal method).

那么具体该怎么做呢?
我们来看下面的这个例子:
 

TAAAAAAA

天王
管理成员
2024/06/16
273
4
38
1,270
Class variables 类变量

Just like you have instance variables that are linked to instances of the class, class variables exist only on the class itself, and are thus always the same no matter how you access it (different instances of the same class can have different values for their instance variables, this isn’t the case with class variables). All variables that start with @@ are class variables.

还有一种变量叫做类变量。
类变量,顾名思义,就是跟类本身相关联的变量。
也就是说,实例有实例方法和实例变量,类同样有类方法和类变量。
我们来看下面的例子:


We have no way to access this variable outside of the class currently, so we have to create some more getter and setter methods. Since we’re dealing with class variables that are shared across all instances of the class, we should make them class methods:

那么我们就来新创建一些类方法吧,请看下面的示例:


You might not realize why this is a class variable and not an instance variable, but class variables aren’t different per object - each object has the same value of that class variable (technically, they don’t even carry around the variable to begin with; the class itself does that. Instances just look it up in the class), so changing its value means it would change the value everywhere, which can lead to unexpected or unwanted results, such as shown below:

实例变量是跟随实例的,也就是说每一个实例的同一个实例变量的值可能是不同的。
而类变量是跟随类的,对于这个类的所有实例来说,每一个实例的同一个类变量的值都是相同的。
我们来看下面的这个例子:


As useless as class variables might seem (and frankly, you’ll hardly ever use them), they do actually have their uses. What if we wanted to count how many instances we’ve ever created of a class, for instance? We’d have a class variable (independent of any instances) be incremented by 1 every time the constructor is called.

在上面的例子中,我们也可以发现,类变量和实例变量一样,可以在整个类的作用域内被自由访问,不论方法本身是实例方法还是类方法。
我们来看一个使用类变量的例子:
 

TAAAAAAA

天王
管理成员
2024/06/16
273
4
38
1,270
Global variables 全局变量

Another type of variables are global variables. As the name implies, these are global can be accessed from everywhere, at any time, in any scope. Unlike constants that are tied to a specific scope, global variables are everywhere. Where instance variables use @ to differentiate them from other variable types, global variables are preceded by a $ sign.

还有一种变量叫做全局变量。
全局变量,顾名思义,就是可以在任何地方、任何时候被访问的变量。
我们在变量的名字前加一个“$”来定义全局变量。
我们来看下面的例子:


Global variables are generally more memory-heavy though, so you shouldn’t go overboard with them.

本章完。
 

在线成员

现在没有成员在线。

最新帖子

论坛统计

主题
540
消息
2,458
成员
3,089
最新成员
未白镇——诺亚