在Ruby中使用属性

Look at any object oriented code and it all more or less follows the same pattern. Create an object, call some methods on that object and access attributes of that object. There's not much else you can do with an object except pass it as a parameter to another object's method. But what we're concerned with here is attributes.

查看任何面向对象的代码 ,它们或多或少遵循相同的模式。 创建一个对象,在该对象上调用一些方法并访问该对象的属性。 除了将对象作为参数传递给另一个对象的方法外,您无法对对象进行其他处理。 但是我们在这里关心的是属性。

Attributes are like instance variables you can access via the object dot notation. For example, person.name would access a person's name. Similarly, you can often assign to attributes like person.name = "Alice". This is a similar feature to member variables (such as in C++), but not quite the same. There's nothing special going on here, attributes are implemented in most languages using "getters" and "setters," or methods that retrieve and set the attributes from instance variables.

属性就像实例变量,您可以通过对象点符号来访问。 例如, person.name将访问一个人的名字。 同样,您通常可以分配给诸如person.name =“ Alice”之类的属性。 这与成员变量(例如,在C ++中)类似,但功能并不完全相同。 这里没有什么特别的事情,在大多数语言中,属性都是使用“ getter”和“ setter”或从实例变量中检索和设置属性的方法实现的。

Ruby doesn't make a distinction between attribute getters and setters and normal methods. Because of Ruby's flexible method calling syntax, no distinction needs to be made. For example, person.name and person.name() are the same thing, you're calling the name method with zero parameters. One looks like a method call and the other looks like an attribute, but they're really both the same thing. They're both just calling the name method. Similarly, any method name that ends in an equals sign (=) can be used in an assignment. The statement person.name = "Alice" is really the same thing as person.name=(alice), even though there is a space in between the attribute name and the equals sign, it's still just calling the name= method.

Ruby在属性获取器和设置器与普通方法之间没有区别。 由于Ruby灵活的方法调用语法,因此无需区分。 例如, person.nameperson.name()是同一件事,您使用零参数调用name方法。 一个看起来像一个方法调用,另一个看起来像一个属性,但是它们实际上是同一回事。 他们俩都只是在调用name方法。 类似地,任何以等号(=)结尾的方法名称都可以在赋值中使用。 语句person.name =“ Alice”person.name =(alice)确实是同一回事,即使属性名称和等号之间有空格,它仍然只是调用name =方法。

自己实现属性 ( Implementing Attributes Yourself )

Close up of woman's hands using laptop at home
Andreas Larsson/Folio Images/Getty Images
安德烈亚斯·拉尔森(Andreas Larsson)/ Folio Images / Getty Images

You can easily implement attributes yourself. By defining setter and getter methods, you can implement any attribute you wish. Here's some example code implementing the name attribute for a person class. It stores the name in a @name instance variable, but the name doesn't have to be the same. Remember, there's nothing special about these methods.

您可以自己轻松实现属性。 通过定义setter和getter方法,可以实现所需的任何属性。 这是一些实现人员类的name属性的示例代码。 它将名称存储在@name实例变量中,但名称不必相同。 请记住,这些方法没有什么特别的。


 #!/usr/bin/env ruby class Person def initialize(name) @name = name end def name @name end def name=(name) @name = name end def say_hello puts "Hello, #{@name}" end end 

One thing you'll notice right away is that this is a lot of work. It's a lot of typing just to say that you want an attribute named name that accesses the @name instance variable. Luckily, Ruby provides some convenience methods that will define these methods for you.

您会立即注意到的一件事是,这是很多工作。 大量输入只是为了表明您想要一个名为name的属性来访问@name实例变量。 幸运的是,Ruby提供了一些方便的方法,可以为您定义这些方法。

使用attr_reader,attr_writer和attr_accessor ( Using attr_reader, attr_writer and attr_accessor )

There are three methods in the Module class that you can use inside of your class declarations. Remember that Ruby makes no distinction between runtime and "compile time," and any code inside of class declarations can not only define methods but call methods as well. Calling the attr_reader, attr_writer and attr_accessor methods will, in turn, define the setters and getters we were defining ourselves in the previous section.

您可以在类声明中使用Module类中的三种方法。 请记住,Ruby在运行时和“编译时”之间没有区别,并且类声明中的任何代码不仅可以定义方法,还可以调用方法。 依次调用attr_reader,attr_writer和attr_accessor方法将定义上一节中定义的setter和getter。

The attr_reader method does just like what it sounds like it will do. It takes any number of symbol parameters and, for each parameter, defines a "getter" method that returns the instance variable of the same name. So, we can replace our name method in the previous example with attr_reader :name.

attr_reader方法的作用与听起来一样。 它采用任意数量的符号参数,并为每个参数定义一个“ getter”方法,该方法返回相同名称的实例变量。 因此,我们可以将上一个示例中的name方法替换为attr_reader:name

Similarly, the attr_writer method defines a "setter" method for each symbol passed to it. Note that the equals sign need not be part of the symbol, only the attribute name. We can replace the name= method from the previous example with a call to attr_writier :name.

同样, attr_writer方法为传递给它的每个符号定义一个“ setter”方法。 请注意,等号不必是符号的一部分,而只需是属性名称。 我们可以使用对attr_writier:name的调用来替换上一个示例中的name =方法。

And, as expected, attr_accessor does the job of both attr_writer and attr_reader. If you need both a setter and getter for an attribute, it's common practice not to call the two methods separately, and instead call attr_accessor. We could replace both the name and name= methods from the previous example with a single call to attr_accessor :name.

而且,正如预期的那样, attr_accessor可以同时完成attr_writerattr_reader的工作 。 如果您同时需要属性的设置器和获取器,通常的做法是不分别调用这两个方法,而是调用attr_accessor 。 我们可以更换的名称 名称=从前面的例子中有一个调用attr_accessor方法:名称


#!/usr/bin/env ruby def person attr_accessor :name def initialize(name) @name = name end def say_hello puts "Hello, #{@name}" end end

为什么要手动定义Setter和Getters? ( Why Define Setters and Getters Manually? )

Why should you define setters manually? Why not use the attr_* methods every time? Because they break encapsulation. Encapsulation is the principal that states no outside entity should have unrestricted access to the internal state of your objects. Everything should be accessed using an interface that prevents the user from corrupting the internal state of the object. Using the methods above, we've punched a big hole in our encapsulation wall and allowed absolutely anything to be set for a name, even obviously invalid names.

为什么要手动定义二传手? 为什么不每次都使用attr_ *方法? 因为它们破坏了封装。 封装是一种原则,规定任何外部实体都不能不受限制地访问对象的内部状态。 应该使用防止用户破坏对象内部状态的接口访问所有内容。 使用上述方法,我们在封装壁上打了一个大洞,并允许为名称设置任何绝对值,甚至显然是无效的名称。

One thing you'll often see is that attr_reader will be used to quickly define a getter, but a custom setter will be defined since the internal state of the object often wants to be read directly from the internal state. The setter is then defined manually and does checks to ensure that the value being set makes sense. Or, perhaps more commonly, no setter is defined at all. The other methods in the class function set the instance variable behind the getter in some other way.

您经常会看到的一件事是attr_reader将用于快速定义getter,但由于将通常希望直接从内部状态读取对象的内部状态,因此将定义自定义setter。 然后手动定义设置器,并进行检查以确保所设置的值有意义。 或者,也许更常见的是,根本没有定义setter。 类函数中的其他方法以其他方式将实例变量设置在getter之后。

We can now add an age and properly implement a name attribute. The age attribute can be set in the constructor method, read using the age getter but only manipulated using the have_birthday method, which will increment the age. The name attribute has a normal getter, but the setter makes sure the name is capitalized and is in the form of Firstname Lastname.

现在,我们可以添加年龄并正确实现name属性。 可以在构造函数方法中设置age属性,使用age getter读取该属性,但只能使用have_birthday方法进行操作,这会增加age。 name属性具有一个普通的getter,但是setter可以确保名称使用大写形式,并且采用Firstname Lastname的形式。


#!/usr/bin/env ruby class Person def initialize(name, age) self.name = name @age = age end attr_reader :name, :age def name=(new_name) if new_name =~ /^[A-Z][a-z]+ [A-Z][a-z]+$/ @name = new_name else puts "'#{new_name}' is not a valid name!" end end def have_birthday puts "Happy birthday #{@name}!" @age += 1 end def whoami puts "You are #{@name}, age #{@age}" end end p = Person.new("Alice Smith", 23) # Who am I? p.whoami # She got married p.name = "Alice Brown" # She tried to become an eccentric musician p.name = "A" # But failed # She got a bit older p.have_birthday # Who am I again? p.whoami

翻译自: https://www.thoughtco.com/using-attributes-2908103

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值