为什么乘法在Ruby中并不总是可交换的?

时间:2017-07-30 14:42:18

标签: ruby multiplication commutativity

如果x是非整数,我得到这个结果:

x = "a"
x * 6 #=> aaaaaa
6 * x #=> TypeError: String can't be coerced into Fixnum

如果x是整数:

x = 6
x * 6 #=> 36
6 * x #=> 36

奇怪的是,如果x是非整数,则乘法中的操作数顺序很重要,而x是整数时则不然。有人可以解释这背后的理性是什么吗?当x是字符串时,为什么变量x必须位于*运算符之前,以避免引发错误?

3 个答案:

答案 0 :(得分:4)

  1. 您的后一段代码中有拼写错误:它应以x = 6开头(不含引号。)

  2. Ruby中的所有内容都是一个对象,包括StringInteger,甚至nil的实例,它们是[{1}}的唯一实例。

  3. 那就是说,没有只是一个运营商 NilClass。这是一个简单的旧方法,在不同的类上声明,由运算符* 调用(感谢@SergioTulentsev提供挑剔的措辞评论。)这是String#*的文档,其他你可能会发现自己。 *不是别的,而是:

    "a" * 6

    您可以在控制台中检查以上内容:它是完全有效的Ruby代码。因此,不同的类具有"a".*(6) 方法的不同实现,因此上面的结果不同。

答案 1 :(得分:4)

您正在尝试三种模式:

  • 一个。 string * numeric
  • numeric * string
  • ℃。 numeric * numeric

方法的行为和所需的参数主要取决于方法左侧的内容(本例中为*),定义方法。没有方法(包括*)本身是可交换的。

String#*要求第一个参数为数字,即a。满足,Numeric#*要求第一个参数为数字,c。满足,和b。没有。

答案 2 :(得分:3)

您需要了解方法*的作用。 1 。这取决于方法的接收器。对于"cat".*(3)"cat"*的接收者。对于1.*(3)(如后面所述,可以编写,1*31*的接收者。术语“接收器”源于OOP向接收器发送消息(方法)的概念。

可以通过两种方式之一在对象(例如,"cat"1)上定义方法。最常见的是该方法是在接收者的类上定义的实例方法(例如,*"cat".class #=> String上定义的1.class #=> Integer。第二种方式,这里不适用,是方法已在对象的单例类上定义,前提是该对象有一个。("cat"有一个单例类,但是1,是一个立即值,不会。)

因此,当我们看到"cat".*(3)时,我们会查看String#*的文档并得出结论

"cat".*(3) #=> "catcatcat"

对于1*(3),我们期待Integer#*,它告诉我们

1.*(3) #=> 3

让我们尝试另一个:[1,2,3].*(3),因为[1,2,3].class #=> Array我们期待Array#*并得出结论

[1,2,3].*(3) #=> [1, 2, 3, 1, 2, 3, 1, 2, 3]

请注意,此方法有两种形式,具体取决于其参数是整数(如此处)还是字符串。在后一种情况下

[1,2,3].*(' or ') #=> "1 or 2 or 3"

许多方法都有不同的行为,这取决于它的参数(以及是否提供了可选块)。

最后,Ruby允许我们使用这三种方法的简写(以及其他名称由不是字母,数字或下划线的字符组成的其他方法):

"cat"*3     #=> "catcatcat"
"cat" * 3   #=> "catcatcat"
1*3         #=> 3
[1,2,3] * 3 #=> [1, 2, 3, 1, 2, 3, 1, 2, 3]

这种速记通常被称为“语法糖”。

1 Ruby的方法名称不限于单词,例如“map”,“upcase”  等等。例如,“*”,“〜”,“[]”和“[] =”是有效的方法名称“