在 Ruby 中, coerce() 方法可以知道哪个运算符需要帮助进行强制转换吗?

发布于 2024-09-01 05:59:20 字数 649 浏览 13 评论 0原文

在 Ruby 中,似乎可以通过 coerce() 来完成很多帮助

def coerce(something)
  [self, something]
end

,当

3 + rational

需要时,Fixnum 3 不知道如何处理添加 Rational,因此它询问 Rational#coerce通过调用rational.coerce(3)来寻求帮助,这个coerce实例方法会告诉调用者:

# I know how to handle rational + something, so I will return you the following:
[self, something]
# so that now you can invoke + on me, and I will deal with Fixnum to get an answer

那么如果大多数操作符都可以使用这个方法,但在(a - b) != (b - a)情况下不能使用呢? coerce() 是否可以知道它是哪个运算符,并仅处理这些特殊情况,同时仅使用简单的 [self, some] 来处理 (a op b) == (b op a) 的所有其他情况? (op是运算符)。

In Ruby, it seems that a lot of coerce() help can be done by

def coerce(something)
  [self, something]
end

that's is, when

3 + rational

is needed, Fixnum 3 doesn't know how to handle adding a Rational, so it asks Rational#coerce for help by calling rational.coerce(3), and this coerce instance method will tell the caller:

# I know how to handle rational + something, so I will return you the following:
[self, something]
# so that now you can invoke + on me, and I will deal with Fixnum to get an answer

So what if most operators can use this method, but not when it is (a - b) != (b - a) situation? Can coerce() know which operator it is, and just handle those special cases, while just using the simple [self, something] to handle all the other cases where (a op b) == (b op a) ? (op is the operator).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏有森光若流苏 2024-09-08 05:59:20

强制的重点不在于知道您要执行什么操作。其目的是使论点和自我达成共识。此外,相同的运算符在某些类中可以是可交换的,而在其他类中则不能(例如,Numeric#+Array#+),因此您的小型基于交换性的 强制利用确实不会有回报。

您应该创建一个新类(例如,ScalarPoint),并使用它来连接标量值,而不是强制强制去做它不打算做的事情。与您的 Point:

class ScalarPoint
  attr_reader :val

  def initialize(val)
    @val = val
  end

  def +(arg)
    case arg
    when Point:
      Point.new(@val + arg.x, @val + arg.y)
    when ScalarPoint:
      ScalarPoint.new(arg.val + @val)
    else
      raise "Unknown operand!"
    end
  end

  # define other operators, such as * etc

  def coerce(arg)
    return [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
    raise "Can't handle"
  end
end

class Point
  def coerce(arg)
    [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
    raise "Can't handle"
  end
end

(注意:代码未测试)

The point of coerce is not to know what operation you are trying to perform. Its purpose is to bring the argument and self to a common ground. Additionally, same operators can be commutative in certain classes, and not in other (Numeric#+ and Array#+, for example), so your small commutativity-based coerce exploit really won't pay off.

Instead of pushing your coerce to do what it's not intended to, you should create a new class instead (such as ScalarPoint, for example), and use it to interface scalar values with your Point:

class ScalarPoint
  attr_reader :val

  def initialize(val)
    @val = val
  end

  def +(arg)
    case arg
    when Point:
      Point.new(@val + arg.x, @val + arg.y)
    when ScalarPoint:
      ScalarPoint.new(arg.val + @val)
    else
      raise "Unknown operand!"
    end
  end

  # define other operators, such as * etc

  def coerce(arg)
    return [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
    raise "Can't handle"
  end
end

and

class Point
  def coerce(arg)
    [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
    raise "Can't handle"
  end
end

etc. (NB: code not tested)

一城柳絮吹成雪 2024-09-08 05:59:20

这个问题的答案是,您可以通过查看回溯来了解运算符,但您不应该这样做。

Ruby 的强制机制并不是这样设计的。正如我在你之前的问题中回答的那样,coerce 应该返回两个等价的值[a, b],这样无论操作符是什么,a.send(operator, b) 都可以工作。

The answer to this question is that you can know the operator by looking at the backtrace but you shouldn't do that.

That is not how the coerce mechanism of Ruby has been designed. As I answered in your previous question, coerce should return two equivalent values [a, b] such that a.send(operator, b) will work, whatever the operator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文