11

我在 pry REPL 中闲逛,发现了一些非常有趣的行为:波浪号方法。

看起来 Ruby 语法有一个内置的文字一元运算符~, 就坐在那里。

这意味着~Object.new将消息发送~到以下实例Object

class Object
  def ~
    puts 'what are you doing, ruby?'
  end
end
~Object.new #=> what are you doing, ruby?

这看起来很酷,但很神秘。Matz 是否本质上是想给我们自己的可定制的一元运算符?

我在 ruby​​docs 中可以找到的唯一参考是在运算符优先级注释中,它被列为最高优先级运算符,与!andunary +这对一元运算符有意义。(有关接下来两个优先级的有趣勘误表**unary -请查看此问题。)除此之外,没有提及此实用程序。

~=,在!~ , and~>` 问题中,我可以通过搜索找到对这个运算符的两个值得注意的引用,即thisthis。他们都注意到它的有用性、古怪性和默默无闻,而没有深入探讨它的历史。

在我即将注销~作为为您的对象提供自定义一元运算符行为的一种很酷的方式之后,我找到了它在 ruby​​ 中实际使用的地方——fixnum(整数)。

~2返回-3~-1返回1。所以它否定一个整数并减去一个......出于某种原因?

任何人都可以启发我作为波浪号运算符在整个 ruby​​ 中的独特和意外行为的目的吗?

4

5 回答 5

4

使用 pry 检查方法:

show-method 1.~

From: numeric.c (C Method):
Owner: Fixnum
Visibility: public
Number of lines: 5

static VALUE
fix_rev(VALUE num)
{
    return ~num | FIXNUM_FLAG;
}

虽然这对我来说是难以理解的,但它促使我寻找一个 C 一元运算~符。存在一个:它是按位 NOT 运算符,它翻转二进制整数 ( ~1010=> 0101) 的位。出于某种原因,这转换为比 Ruby 中十进制整数的否定小一。

更重要的是,由于 ruby​​ 是一种面向对象的语言,编码其行为的正确方法是定义一个对二进制整数对象执行按位求反~0b1010的方法(我们称之为)。~为了实现这一点,ruby 解析器(这里都是猜想)必须将~obj任何对象解释为obj.~,因此您可以获得所有对象的一元运算符。

这只是一种预感,哪位有更权威或解释清楚的答案,请赐教!

- 编辑 -

正如@7stud 指出的那样,Regexp该类也使用它,基本上将正则表达式与当前范围内$_接收的最后一个字符串匹配。gets

正如@Daiku 指出的那样,Fixnums的按位否定也被记录在案

我认为我的解析器解释解决了为什么 ruby​​ 允许~作为调用Object#~.

于 2013-07-27T02:12:53.857 回答
3

对于fixnum,它是一个的补码,它在二进制中将所有的 1 和 0 翻转为相反的值。这是文档:http ://www.ruby-doc.org/core-2.0/Fixnum.html#method-i-7E 。要了解它为什么给出示例中的值,您需要了解负数如何以二进制表示。为什么 ruby​​ 提供这个,我不知道。 二进制补码通常是现代计算机中使用的补码。它的优点是基本数学运算的相同规则适用于正数和负数。

于 2013-07-27T02:08:21.083 回答
1

~是 Ruby 中的二进制补码运算符。一个补码只是翻转一个数字的位,效果是这个数字现在在算术上是负数。

例如,32 位(Fixnum 的大小)二进制中的 2 是 0000 0000 0000 0010,因此 ~2 将等于 1111 1111 1111 1101 的补码。

然而,正如您已经注意到并且本文进一步详细讨论的那样,Ruby 的反码版本的实现似乎有所不同,因为它不仅使整数为负数,而且还从中减去 1。我不知道为什么会这样,但似乎确实如此。

于 2013-07-27T02:21:57.883 回答
0

它在 pickaxe 1.8 的几个地方都提到过,例如 String 类。但是,在 ruby​​ 1.8.7 中,它不适用于所宣传的 String 类。它确实适用于 Regexp 类:

print "Enter something: "
input = gets
pattern = 'hello'
puts ~ /#{pattern}/

--output:--
Enter something: 01hello
2

对于 String 类,它应该类似地工作。

于 2013-07-27T02:04:51.927 回答
-1
  • 〜(比格努姆)
  • 〜(复杂)
  • 〜(固定数字)
  • 〜(正则表达式)
  • 〜(IP地址)
  • 〜(整数)
  • 〜(正则表达式)

这些中的每一个都记录在文档中。

此列表来自 Ruby 2.6 的文档

这个方法的行为“大体上”基本上是你想要的任何东西,正如你用你~在 Object 类上调用的方法的定义所描述的那样。由实现维护者定义的核心类上的行为似乎有很好的文档记录,因此它不应该对这些对象产生意外行为。

于 2013-07-27T08:36:27.340 回答