Ruby一元代波形(`~`)方法

时间:2013-07-27 01:43:42

标签: ruby syntax operators literals

我在一个狡猾的REPL中闲逛,发现了一些非常有趣的行为:代字号方法。

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

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

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

这看起来很酷,但很神秘。 Matz基本上是想给我们自己定制的一元算子吗?

我在rubydocs中可以找到的唯一引用是在operator precedence注释中,它被排在第一位最高优先级运算符旁边,!unary +这是有道理的对于一元运营商。 (有关接下来两个优先级的有趣勘误,**然后unary -,请查看this question。)除此之外,不提及此实用程序。

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

在我即将注销~作为为对象提供自定义一元操作符行为的一种很酷的方法之后,我找到了一个实际用于ruby的地方 - fixnum(整数)。

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

任何人都可以启发我作为波形符操作符在ruby中的独特和意外行为的目的吗?

5 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:3)

使用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指出的那样,Regexpmakes use of it as well基本上与正则表达式$_相匹配,这是当前作用域中gets收到的最后一个字符串。

正如@Daiku指出的那样,Fixnum s的按位否定是also documented

我认为我的解析器解释解决了为什么ruby允许~作为调用Object#~的全局一元运算符的更大问题。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

在镐1.8的几个地方提到过,例如String类。但是,在ruby 1.8.7中,它不像广告中那样对String类起作用。它适用于Regexp类:

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

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

它应该类似于String类。

答案 4 :(得分:0)

  • 〜(Bignum)
  • 〜(复杂)
  • 〜(Fixnum)
  • 〜(Regexp)

每篇文章均记录在文档中。

此列表来自Ruby 2.0的文档

这个方法“at large”的行为基本上是你想要的,正如你在Object类中定义了一个名为~的方法时所描述的那样。由实现维护者定义的核心类的行为似乎已被很好地记录,因此它不应该对这些对象有意外行为。