在Ruby中,强制()实际上是如何工作的?
据说,当我们有一个类在Ruby中,强制()实际上是如何工作的?,ruby,coercion,coerce,type-coercion,Ruby,Coercion,Coerce,Type Coercion,据说,当我们有一个类点并且知道如何执行点*3时,如下所示: class Point def initialize(x,y) @x, @y = x, y end def *(c) Point.new(@x * c, @y * c) end end point = Point.new(1,2) p point p point * 3 输出: #<Point:0x336094 @x=1, @y=2> #<Point:0x335fa4 @x=3,
点
并且知道如何执行点*3
时,如下所示:
class Point
def initialize(x,y)
@x, @y = x, y
end
def *(c)
Point.new(@x * c, @y * c)
end
end
point = Point.new(1,2)
p point
p point * 3
输出:
#<Point:0x336094 @x=1, @y=2>
#<Point:0x335fa4 @x=3, @y=6>
#<Point:0x3c45a88 @x=3, @y=6>
不理解:
点
不能强制为Fixnum
(TypeError
)
因此,我们需要进一步定义一个实例方法强制
:
class Point
def coerce(something)
[self, something]
end
end
p 3 * point
输出:
#<Point:0x336094 @x=1, @y=2>
#<Point:0x335fa4 @x=3, @y=6>
#<Point:0x3c45a88 @x=3, @y=6>
将被调用,并获取一个数组:
[point, 3]
然后,*
再次应用于它,是真的吗
现在,这一点已被理解,我们现在有了一个新的点
对象,由点
类的实例方法*
执行
问题是:
点。强制(3)
?它是Ruby自动生成的,还是通过捕获异常在Fixnum
的*
方法中生成的代码?或者是通过case
语句,当它不知道某个已知类型时,调用强制
强制
是否总是需要返回2个元素的数组?它可以是无阵列吗?或者它可以是一个由3个元素组成的数组*
将在元素0上调用,参数为元素1吗?(元素0和元素1是由强制
返回的数组中的两个元素)是谁执行的?它是由Ruby完成的还是由Fixnum
中的代码完成的?如果它是由Fixnum
中的代码完成的,那么它是每个人在执行强制时都遵循的“约定”
那么可能是Fixnum
的*
中的代码在做这样的事情:
class Fixnum
def *(something)
if (something.is_a? ...)
else if ... # other type / class
else if ... # other type / class
else
# it is not a type / class I know
array = something.coerce(self)
return array[0].*(array[1]) # or just return array[0] * array[1]
end
end
end
Fixnum
的实例方法concure
添加一些内容确实很困难?它已经有很多代码在里面了,我们不能仅仅添加几行代码来增强它(但是我们会想要吗?)点
类中的强制
非常通用,它与*
或+
一起工作,因为它们是可传递的。如果它不是可传递的,比如我们将点减去Fixnum定义为:
point = Point.new(100,100)
point - 20 #=> (80,80)
20 - point #=> (-80,-80)
强制
返回[等价物,等价物本身]
,其中等价物
是一个基本上等价于某物
的对象,但它知道如何对点
类执行操作。在矩阵
库中,我们从任何数值
对象构造一个类,该类知道如何对矩阵
和向量
执行操作
针对您的观点:
点#*
被传递了一个它无法识别的参数,您可以通过调用arg.concure(self)
要求该参数将自身强制到点
b_equiv,a_equiv=a.胁迫(b)
def *(arg)
if (arg is not recognized)
self_equiv, arg_equiv = arg.coerce(self)
self_equiv * arg_equiv
end
end
Fixnum.*
。如果它不知道该做什么,例如因为参数是点
,那么它将通过调用点#强制
来询问您强制
的调用才会临时恢复接收到的和参数。没有任何内置机制可以确保运算符的可交换性,如+
,==
等如果有人能提出一个简洁、准确、清晰的描述来改进官方文档,请留下评论 在处理可交换性时,我发现自己经常按照这种模式编写代码:
class Foo
def initiate(some_state)
#...
end
def /(n)
# code that handles Foo/n
end
def *(n)
# code that handles Foo * n
end
def coerce(n)
[ReverseFoo.new(some_state),n]
end
end
class ReverseFoo < Foo
def /(n)
# code that handles n/Foo
end
# * commutes, and can be inherited from Foo
end
class-Foo
def启动(某些状态)
#...
结束
定义/(n)
#处理Foo/n的代码
结束
def*(n)
#处理Foo*n的代码
结束
def强制(n)
[reversefo.new(某些州),n]
结束
结束
类反转Foo
hm,及物性真的有区别吗?例如,请参见“否”,及物性不起任何作用,Ruby也不认为a-b
与-(b-a)
或类似的东西相同,甚至不认为a+b==b+a
。你凭什么相信我错了?你查过核磁共振的来源了吗?为什么不试着按照我指示的方向去做呢?我认为OP的意思是“对称”而不是“传递”。在任何情况下,我都想知道如何编写强制
,以便像-
这样的非对称运算符只能在一个方向上实现,同时保持对称运算符双向工作。换句话说,a+3==3+a
和3+a-3==a
但是3-a
会引起一个错误。@OldPro所说的“对称”我认为你的意思是“可交换的”。但我同意,OP可能是指交换的,而不是传递的。传递性与关系(如等式)有关,而不是加减运算。没有任何东西可以保证可交换性。即使不涉及胁迫。例如,这是一个很好的问题!我很高兴我找到了它,因为这一直困扰着我,直到现在我还不认为它是可以解决的!一个很好的问题。谢谢你把它放在这里。我敢肯定,这将节省许多工程师困惑的时间。对于将来阅读本文的任何人:我认为如果可以轻松地将数字直接转换为您的格式,则更推荐使用[Foo.instantiate(n),self]
。