在ruby中,是否有一种方法可以像内置类型一样获取和设置特定的示例变量?

7kqas0il  于 12个月前  发布在  Ruby
关注(0)|答案(3)|浏览(78)

在ruby中,就像在任何其他语言中一样,我们可以像这样获取和设置内置类型

var1 = 12
if var1 > 10
  var1 = 90
end

现在让我们假设我是一个愚蠢的傻瓜,只想处理(例如)无符号整数,并创建以下类

class UInteger
  attr_accessor :value
  ...
end

有没有一种方法可以模拟内置变量getter和setter,以避免通过调用

uint.value

uint.value = ...

然后换成

uint

uint = ...

6yt4nkrj

6yt4nkrj1#

我们可以像这样获取和设置内置类型[...]
是的,但这绝不限于内置的“类型”。您可以在自定义类的示例中使用完全相同的代码。你只需要提供一个有意义的>方法,例如:(出于演示的目的,该类不做任何有用的事情)

class UInteger
  def initialize(value)
    @value = value.to_i
  end

  def >(other)
    @value > other.to_i
  end

  def to_i
    @value
  end
end

除此之外,代码结构保持不变:

var1 = UInteger.new(12)
if var1 > UInteger.new(10)
  var1 = UInteger.new(90)
end

var1 #=> #<UInteger:0x00007f898992ebf8 @value=90>

你可以添加一个全局方法UInteger()来更容易地创建新示例(就像BigDecimal一样),也可以添加一个自定义的inspect方法,它类似于它的语法,用于技术性较低的输出:

class UInteger
  # ...

  def inspect
    "UInteger(#{@value})"
  end
end

def UInteger(value) = UInteger.new(value)

通过上述更改,代码变为:(这些变化纯粹是装饰性的,它仍然是UInteger的示例,就像以前一样)

var1 = UInteger(12)
if var1 > UInteger(10)
  var1 = UInteger(90)
end

var1 #=> UInteger(90)

当然,UInteger示例 * 不是 * 一个实际的整数。如果你需要一个整数值,你必须转换它,例如:

var1 = UInteger(90)

var1.to_i #=> 90

这与从内置类(如string)转换示例没有什么不同:

var1 = "90"

var1.to_i #=> 90
wribegjk

wribegjk2#

如前所述,您不能更改Ruby文字,您不能调用uint并返回Integer的示例而不是UInteger
可能需要整数的decorator

class UInteger
  attr_accessor :value

  def initialize(value)
    raise ArgumentError unless value.is_a?(Integer)
    @value = value
  end

  def to_s
    @value.to_s
  end

  def inspect
    @value.inspect
  end

  private

  def respond_to_missing?(name, include_private = false)
    @value.respond_to?(name, include_private)
  end

  def method_missing(method, *args, &block)
    @value.send(method, *args, &block)
  end
end

或使用Active Support库的delegate和delegate_missing_to方法

require 'active_support/core_ext/module/delegation'

class UInteger
  attr_accessor :value

  delegate_missing_to :@value
  delegate :to_s, :inspect, to: :@value

  def initialize(value)
    raise ArgumentError unless value.is_a?(Integer)
    @value = value
  end
end

然后你可以在这个UInteger中添加一些特定的方法,目前它是虚拟的,只是重复整数功能
用法示例

uint10 = UInteger.new(10) # => 10
uint20 = UInteger.new(20) # => 20

uint10.class # => UInteger

uint10 + uint20 # => 30
uint10 + 20 # => 30
uint10 > uint20 # => false
uint10 > 20 # => false
# etc.
r55awzrz

r55awzrz3#

我的感觉是你在问是否可以在Ruby中创建一个自定义的文字,因为这是文字(字符串,整数,布尔值等)在Ruby中的行为方式。答案是no
这对于Object类来说似乎是故意的,您的UInteger类将自动继承它。由于您可以覆盖Object class上的任何方法,因此允许您覆盖对象本身的调用可能会产生大量问题。假设我这样做:

class UInteger
  attr_accessor :value, :timestamp
end

uint = UInteger.new
uint.value = 5

如果我可以将uint重写为uint.value,那么我就不能调用uint.timestamp

uint 
#=> 5

uint.class
#=> Integer

uint.timestamp
#=> NoMethodError

如果我可以将uint =重写为uint.value =,那么我总是将uint重写为一个uint.value =

uint = UInteger.new
#=> true

uint.class
#=> UInteger

uint = 5
#=> true

uint
#=> 5

uint.class
#=> Integer

相关问题