ESS多版本 【TA】【ESS】06 类和对象

TAAAAAAA

天王
成员
2024-06-16
173
1
27
1,110
6: Classes and objects 类和对象

Variables stores values of a certain type. The best way to refer to that is with object. The number 10 is an object. If you assign 10 to a variable (e.g. my_var = 10), the variable will have the object of 10. The type of the object is the same as the value’s type (data type), we’ll just be referring to it differently.

变量可以存储某一种类型的数据,在Ruby中,任何数据都是对象,所以数据的类型也就是对象的类型。
数字10是一个对象,如果你写my_var = 10,那么my_var这个变量就指向了对象10。

A variable stores an object for when you need to use it multiple times, such as this:

当你用一个变量存储了一个对象时,你就可以随时使用这个对象了。

Ruby:
gender = 0
# 0是一个对象,gender存储了这个对象。

But an object doesn’t have to be associated with a variable.

但是,对象并不一定要和变量相关联,请看下面的例子:

Ruby:
gender = 0
life_expectancy = [79,80][gender]

There are three objects in this example:
0
79
[79,80]

在上面的例子中,总共有3个对象,分别是0、79和[79, 80]。
79这个对象是通过[79, 80][gender]计算得出的。

Out of these, 0 and 79 can be reused because they’re associated with a variable (gender and life_expectancy). The array [79,80] is still an object and a newly created array, but once the line life_expectancy = [79,80][gender] is done, [79,80] is no longer accessible. The object is disposed by the garbage collector (which is just something that deletes old unreachable objects/code to lower RAM usage), because there’s no way to access [79,80], as it isn’t a variable.

在上面的例子中,0和79可以随时使用,因为它们和变量关联在了一起,我们可以通过变量随时访问对应的对象。
但是,对于[79, 80]这个对象,在life_expectancy = [79, 80][gender]这一行运行结束之后,我们将不再能访问它,因为这个对象并没有指向任何一个变量,所以在life_expectancy = [79, 80][gender]这一行运行结束之后,[79, 80]这个对象就会被程序清除,用以节省内存。

当你看到我写“指向了”、“存储了”、“保存了”、“赋予了”、“关联了”,等等的词时,它们都是一个意思,就是指的那个对象是否有变量和它相关联,我们是否可以通过变量访问那个对象。
 

TAAAAAAA

天王
成员
2024-06-16
173
1
27
1,110
Classes and conditions 类和条件

The data type of an object (such as Fixnum, String, Float, Array, Range) is also called the class of the object. An object of class Fixnum (such as 10) is an instance of that class. The class provides information as to what the class does and what it looks like, and 10 basically fills in the missing details like the value. You can think of classes like the structure of the object.

一个对象的数据类型被称为这个对象的类。
也就是说,一个对象的数据类型是什么,它的类就是什么。
某一个类的对象被称为这个类的实例。

如果你听不懂有点绕的话,我们可以用人来理解。
你是一个人,所以你是一个对象;
你的数据类型就是你的类,很明显,你是人类,你不是狗类,更不是猫类;
你是人类这个类的一个具体的、特定的、单独的个体,也就是实例(一个实实在在存在的人的例子)。

再比如说数字10,10是一个整数,所以10的类是整数类,10是整数这个类的一个实例。

也就是说,类提供了对于某一个东西到底是什么的一个大致的框架结构。
人类是一个类,而你是人类的一个实例,人和人之间可以如此不同,但是,人和人之间再怎么不同,你也不会把一个人当成是狗,人永远不会是狗。

当你看到我有时候写“对象”,又时候又写“实例”,它们其实是一样的,某一个对象必定是某个类的一个实例。

To programmatically determine the class of an object, you can use the .class method on the object.

为了知道一个对象的类是什么,我们可以使用对这个对象使用class命令,请看下面的例子:

Ruby:
print "a".class #=> String # 字符串类
print 1.class #=> Fixnum # 整数类
print 3.14.class #=> Float # 浮点数类
print [1,2,3].class #=> Array # 数组类
print (1..3).class #=> Range # 范围类
print true.class #=> TrueClass # 真类
print false.class #=> FalseClass # 假类
print nil.class #=> NilClass # 空类

a = "hello"
print a.class #=> String

Technically, this means you could write code like this:

也就是说,我们也可以通过检查某一个对象是否是某一个类来当作if的条件,请看下面的例子:

Ruby:
var = "17"
if var.class == Fixnum
  print "var is a number!"
elsif var.class == String # This is true
  print "var is a string!"
else
  print "var is something else!"
end

Fixnum, String, Array, Range, FalseClass and such may refer to the class the object is an instance of, but that too is actually an object; an object of type Class.

在Ruby中,Fixnum、String、 Array、Range和FalseClass等等这些类本身也是对象,它们是更高级别的类(Class类,也就是类类)的对象。

However, there is a method for this on all objects which you should use instead: .is_a?(class). Just why you should use this and why there’s a difference will be covered in 7: Classes and polymorphism.

我们可以直接使用is_a?(xxx)(是一个?)来检查某一个对象是否是某一个类,其中xxx就是你要检查的类,我们来看下面的这个例子:

Ruby:
var = [17]
if var.is_a?(Fixnum)
  print "var is a number!"
elsif var.is_a?(String)
  print "var is a string!"
elsif var.is_a?(Array) # This is true
  print "var is an array!"
else
  print "var is something else!"
end

Another quick example:

再来看另一些例子:

Ruby:
print [1].is_a?(Array) #=> true
print 3.14.is_a?(Float) #=> true
print 3.14.is_a?(Array) #=> false
 
最后编辑:

TAAAAAAA

天王
成员
2024-06-16
173
1
27
1,110
Classes and instance methods 类和实例方法

To reiterate one of the first things you learned:

我们来看一下下面这些你已经学过的内容:

Ruby:
var = 10
var *= 2
print var #=> 20

var *= 2 is equal to var = var * 2, which, in this case (because var is 10), would be 10 * 2. This multiplication is actually an instance method on the Fixnum class. Just like we saw with arrays (array.size, array.delete_at, array.push), it calls a method on the object 10; the * method. Another completely valid (and standard) way to perform 10 * 2 would be 10.*(2).

在这个例子中,我们知道,var *= 2,其实就是 var = var * 2,而又因为var是10,所以其实就是var = 10 * 2。
在这里的“*”(乘),实际上就是整数类里面的一个实例方法。
我们之前学数组时学过的size、delete_at和push等等的这些其实就是数组类里面的实例方法。
实例方法,顾名思义,就是用在实例上的方法。
所以,我们可以对某一个实例调用这个实例所在的类里面的实例方法。

This is essentially the method below, but then for the Fixnum class:

我们来看一下“*”这个实例方法大概可能是怎么写的:

Ruby:
def *(number2)
  return some_way_to_perform_the_calculation(number2)
end

This kind of notation (10 * 2) isn’t possible to replicate; it, again, is just a built-in, hard-coded shortcut in Ruby (and basically every other Object Oriented Programming language). It’s just a thing you have to accept.

As mentioned, 10 is an object of the Fixnum class. The Fixnum class provides a layout or structure for what 10 should do, and also provides the methods for it. These are called instance methods.

之前我们也已经是说过了,10是一个对象,它是整数类的。
整数类这个类提供了10的各项属性,即10应该是怎么样的,以及它可以使用的实例方法有哪些。
你还是可以拿人来理解,人类这个类提供了人的各项属性,比如身高、体重和肤色,等等等等,以及人可以使用的实例方法,即人可以做哪些动作,比如走、跑和跳,等等等等。

If you try to multiply something that isn’t a number though (such as nil), you’ll get an error similar to this:

如果你对一个不是数字的对象使用了“*”,那么程序就有可能会报错,因为不是所有的对象都有“*”这个实例方法,请看下面的这个例子:

Ruby:
ar = nil
var *= 2 #=> NoMethodError: Undefined method '*' for nil:NilClass
# 没有方法错误:空类没有一个叫做“*”的方法。
# 这里出现了nil:NilClass,这其实是xxx:yyy这样的一个结构,xxx就是
# 这个对象,yyy就是这个对象的类。

This would translate to nil.*(2), but the NilClass doesn’t provide an instance method called *, whereas Fixnum does. (nil:NilClass stands for <object>:<class>; object is whatever object it’s looking for the method in, and class is the class of that object). It’s just like calling a method that doesn’t exist, but then for an object.

Ruby:
def methA
  print "Called methA!"
end

methB #=> Undefined method 'metB' for main:Object
# 这里同样的,对于main这个对象,在Object(对象类)类里
# 并没有一个叫做methB(兴奋剂B?)的方法。
# 哈哈,这里的meth其实是method的简写。
# 这里的main,其实指的是主作用域。

(main is something internal we’ll cover in a future tutorial - it just means it’s referring to the main scope, and not a class of some kind.)

Whenever we write <Class>#<Method> in documentation or elsewhere, we refer to the instance method called <Method> of the <Class> class. 10.*(2) would be Fixnum#* with an argument of 2. nil.*(2) is NilClass#* with an argument of 2, too.

当我们写xxx#yyy这样的结构时,其实xxx指的就是类,yyy指的就是类的实例方法。
比如说,对于nil.*(2),就是NilClass#*,你可能会说不是还有个2吗,对,但是2其实是*的参数。
 
最后编辑:

TAAAAAAA

天王
成员
2024-06-16
173
1
27
1,110
Different methods per class 不同类的同名方法

While 10 * 2 performs a multiplication and nil * 2 raises an error, strings and arrays do have a different use for <object> * 2. This heavily depends per class, but when you try to multiply a string, it’ll just copy-paste the content of the string N times, where N is the amount you’re multiplying with.

在不同的类中,可以具有同名的方法,比如说在AAA类中有一个叫做aaa的方法,在BBB类中也有一个叫做aaa的方法。
但是,虽然方法的名字一样,方法所做的事情却可能并不一样。
也就是说,你对AAA的实例调用aaa和对BBB的实例调用aaa,结果可能是天差地别的。
我们来看下面的例子:

Ruby:
var = "a"
var *= 3
print var #=> "aaa"
# 可以看到,对于字符串类的实例,*就是把原字符串变成了相应的个数(1→3)。

var *= 3
print var #=> "aaaaaaaaa"

Unlike NilClass, String does have a * method. It just does something different than multiplication. Array has one too:

Ruby:
var = [1]
var *= 3
print var #=> [1,1,1]
# 可以看到,对于数组类的实例,*就是把元素变成了相应的个数(1→3)。

var = [1,2,3]
var *= 3
print var #=> [1,2,3,1,2,3,1,2,3]
 

TAAAAAAA

天王
成员
2024-06-16
173
1
27
1,110
Object assignment vs variable assignment 对象指定 vs 变量指定

An important thing to understand is that you can only assign to variables, and not to objects.

我们只能为变量指定值,不能为对象指定值(这似乎是显而易见的事情)。
来看下面的几个例子:

Ruby:
var = "Hello!" * 2
print var #=> "Hello!Hello!"

This works perfectly fine; we’re performing “Hello!”.*(2) and setting var to the result of that, and then print it out.

However, if we wanted to do something like this, we’d get an error.

Ruby:
"Hello!" = "Hello!" * 2

"Hello!" = 3.14

Both of these raise a SyntaxError when trying to start the script, stating “unexpected ‘=’”. This is because “Hello!” is an object, and you cannot assign to an object. Objects are temporary, unless stored somewhere (such as a variable or array). And only variables/arrays can be assigned to with =.
 

TAAAAAAA

天王
成员
2024-06-16
173
1
27
1,110
Improper arguments 不正确的参数

While 10 * 2 and 2 * 10 might do the same, that’s not the case when you try to multiply different data types.

我们在调用方法时,需要使用正确的参数。

Fixnum#* expects a Fixnum or a Float.
String#* expects a Fixnum or a Float.
Array#* expects a Fixnum or a Float.

Now take “a” * 3 as an example. This calls String#* with a Fixnum, so this works fine. But if you reversed it, 3 * “a”, we’re calling Fixnum#* with a String. This raises an error, because Fixnum#* only accepts Fixnums and Floats - not Strings. The same applies to Arrays.

我们来看一个例子,”a” * 3和 3 * ”a”是不一样的,前者是String#*加一个参数3,而后者是Fixnum#*加一个参数”a”。
当你分别运行时,前者没有什么问题,后者会报错。
为什么呢,因为前者你是对一个字符串调用*,字符串类里的*是接受一个整数3作为参数的,但是后者你是对一个整数调用*,整数类里的*并不接受字符串作为参数。
所以,在你写代码的时候,一定要时刻想清楚,你是对什么调用什么方法。
这一小节其实也可以看做是之前不同类的同名方法的一个额外补充。

下面是作者写的让整数类的*也支持字符串参数的一个替代方法:

This isn’t something internal, but rather a design choice. You can write your own code in a way that supports both ways, or you can write something that only supports one way - it’s up to you to figure out what you want.

Two examples of normal methods below, illustrating different ways you can write it.

Ruby:
def mult(a, b)
  if a.is_a?(Fixnum) || a.is_a?(Float)
    if b.is_a?(Fixnum) || b.is_a?(Float)
      return a * b
    else
      return "You can't multiply #{a.class} with #{b.class}!"
    end
  elsif a.is_a?(String) || a.is_a?(Array)
    if b.is_a?(Fixnum) || b.is_a?(Float)
      return a * b
    else
      return "You can't multiply #{a.class} with #{b.class}!"
    end
  else
    return "You can't multiply #{a.class} with #{b.class}!"
  end
end

print mult("hi",3) #=> "hihihi"
print mult(3,3) #=> 9
print mult(3,"hi") #=> "You can't multiply Fixnum with String!"
print mult(3,1..3) #=> "You can't multiply Fixnum with Range!"

Ruby:
def mult(a, b)
  if a.is_a?(Fixnum) || a.is_a?(Float)
    if b.is_a?(Fixnum) || b.is_a?(Float)
      return a * b
    elsif b.is_a?(String) || b.is_a?(Array)
      return b * a
    else
      return "You can't multiply #{a.class} with #{b.class}!"
    end
  elsif a.is_a?(String) || a.is_a?(Array)
    if b.is_a?(Fixnum) || b.is_a?(Float)
      return a * b
    else
      return "You can't multiply #{a.class} with #{b.class}!"
    end
  else
    return "You can't multiply #{a.class} with #{b.class}!"
  end
end

print mult("hi",3) #=> "hihihi"
print mult(3,3) #=> 9
print mult(3,"hi") #=> "hihihi"
print mult(3,1..3) #=> "You can't multiply Fixnum with Range!"

As you can see, it really is just a choice you make here. Ruby chose not to support 3 * "hi", but it’s really up to you what you support and what you don’t.

本章完。
 
最后编辑:

在线成员

现在没有会员在线。

论坛统计

主题
458
消息
2,073
会员
2,857
最新会员
静候you

关于我们

  • 宝可梦以及其他相关名称是任天堂的商标,版权归宝可梦公司所有。宝可饭堂是一个同人游戏中文社区,不隶属于宝可梦公司。在宝可饭堂上的粉丝游戏亦未获得其授权,请支持正版游戏。
© 2022- pokefans.cn
点此延长宝可饭堂生命