博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Instance Variables in ruby
阅读量:6256 次
发布时间:2019-06-22

本文共 10396 字,大约阅读时间需要 34 分钟。

 

Dogs have many shared characteristics, like the abilities to wag their tails and drink water from a bowl, but they also have information about them that is variable,

like their breed or their name.

Similarly, when designing an application, your users will have common traits, like the ability to log in and out, but some information will be variable,

like a username or email address. Let’s start by setting up a new User class. You can follow along in either irb or by running a script from the command line.

class User    # stuff will go hereend

By the end of this lesson, you’ll be able to define a User class that can track its own user information.

 

Say you wanted to assign a user’s username. You might try something like this.

julia = User.newjulia.username = "coolgirl2000"# NoMethodError: undefined method `username' for #

Let’s pause to take a look at that error bit by bit.

  • NoMethodError: If I had to guess, I’d say this likely has something to do with a method not existing.
  • undefined method 'username': Suspicions confirmed. It looks like our code can’t find a 'username' method. That makes sense, we never defined one.

But you weren't trying to create a new method! You were thinking about this username like a variable, right?

Ruby has no way of distinguishing between variables and methods in this case, since they both come after the ., so it only supports instance methods.

?What do we do now?! To treat username as a variable, you’re going to need to fake this a bit. Let’s write just enough code to stop this pesky error.

class User  def username=(value)  endend

If you recall, most characters are fair game with methods, including =. In this case, the valueargument stands in place of the value you want to assign to username.

julia.username=("coolgirl2000")# => "coolgirl2000"

That does the trick… sort of. There’s an awful lot of syntax here, and it’s a bit of a stretch to say this looks anything like the julia.username = “coolgirl2000” we were going for.

Luckily, we can leave off the parentheses since those are optional for methods. These little shortcuts are known as syntactic sugar, since they make writing code with it just a bit sweeter ?. Let’s see how that looks.

julia.username= "coolgirl2001"# => "coolgirl2001"

Wow, I already feel so much less stressed looking at that. The fact that the = is pressed up againstusername is still bothering me. I can’t stop looking at it.

It’s going to bother me forever if you don’t do something about it. Please, do something about it.

Syntactic sugar to the rescue again. When a method ends with =, Ruby rightfully assumes that you’re creating a method for variable assignment. To make your life sweeter, Ruby lets you put a space before the = so it reads more like typical variable assignment, like so:

julia.username = "coolgirl2002"# => "coolgirl2002"

?Boom. Check that out. I can sleep easily again. You’ve just successfully created (the start of) asetter method (sometimes called a mutator method).

A setter method is one which sets, or changes, the value of a variable belonging to a particular object.

 

Alright, let’s check in on your username. If my math is correct, it should be set to “coolgirl2002”right now.

julia.username# NoMethodError: undefined method `username' for #

This error again. You’ve seen this one before, but didn’t you already create this instance method?

Let’s go ahead and write the bare minimum amount of code to make this error go away.

class User  def username=(value)  end  def username  endend

This is the opposite of a setter method, a getter method. It exists to get the value of a variable belonging to an object. Let’s see if this works.

julia.username# => nil

There’s no error ?, but it’s also returning nil instead of “coolgirl2002”. You may have already caught on to this…

neither your username nor your username= methods actually do anything.

 

To make your getter and setter methods start working, you’re going to need to capture theusername values somewhere.

The problem here has to do with scope. How can the values you capture in the username= setter method be accessed in the username getter method?

Much like instance methods, you can also use instance variables. Instance variables are variables that are scoped to the entire class.

This means that once an instance variable is defined, it can be used anywhere in that object.

An instance variable looks just like a regular variable, with one minor difference: it starts with @.

class User  def username=(value)    @username = value  end  def username    @username  endend

Let’s see if this works before moving on.

julia.username = "coolgirl3000"# => "coolgirl3000"julia.username# => "coolgirl3000"

? Nice!

The @username instance variable is now available to use by any of the methods inside of a Userobject.

You can go ahead and make other User objects now, and each one will be able to track their own information.

walter = User.new# => #
walter.username = "cooldude17"# => "cooldude17"walter.username# => "cooldude17"

And one last check with Julia to make sure her information is still accurate.

julia.username# => "coolgirl3000"

Remember when we said that $global_variables weren’t the best solution? This is that best solution.

Very rarely will you need a variable that is available to everything inside your application. Often, you just want it available to one or a few objects.

Let me say that again: You will almost never need to use global variables ever again. If you find yourself using one,

there’s a very good chance it can be done some other way using classes.

Getter and setter methods are used so often in Ruby that there are even more shortcuts you can use to make your life sweeter.

Why type more code than you really need to? Remember, Ruby is optimized for developer happiness.

class User  attr_reader :username  attr_writer :usernameend

attr_reader and attr_writer (“attr” being shorthand for “attribute”) are two methods that take care of creating getter and setter methods, respectively, for you. 

Best of all, you can do this for as many attributes as you’d like. Perhaps you want users to be able to change their usernames, but not their birthdays.

class User  attr_reader :username, :birthday  attr_writer :usernameend

There’s no need to actually write out all those getter and setter methods yourself anymore!

One thing that confused me at first was the syntax of attr_reader and attr_writer.

It didn’t really look like anything I’d ever seen before, at least not until someone rewrote it for me this way:

attr_reader(:username, :birthday)

These are actually instance methods that are already baked in for you to use.

All you are doing is passing in a Symbol representing the instance variable you’d like to create getter and setter methods for.

Accessors

There’s one last refactor we can do here. It’s pretty common to need both a getter and a setter method for an attribute, so why not define both at once?

That’s exactly what attr_accessordoes.

class User  attr_accessor :usernameend

I know what you’re thinking. Yes, I did just string you along this emotional journey only to end up writing three lines of code.

But think about it: now you know what these three lines of code actually do!

Along the way, you learned about instance variables, some neat syntactic sugar, and getters and setters. Not bad.

Let’s continue with the User example. This is what we’ve got at the moment:

class User  attr_accessor :usernameend

This is useful, but presents a slight issue. We don’t want a user to ever be without a username.

The way things are currently set up, you can easily do something like this:

colt = User.new# => #
colt.username# => nil

Because a User is created without a default username value, Colt is left without a username until he goes in and sets one himself.

?This will not do.

There’s a special instance method you can use to make sure an object is properly set up when it’s created, initialize.

When you create a new object, the first thing Ruby will do is look for thatinitialize method and run it.

This makes is super handy for initial setup (for things like… initializing an object with a username, maybe?).

class User  attr_accessor :username  def initialize    @username = "its_colt_outside"  endend

Let’s give this another go.

colt = User.new# => #
colt.username# => "its_colt_outside"

?Beautiful.

 

There’s just one issue with the previous example— we’re hard-coding “its_colt_outside” to be the default username for every single user.

That’s not going to help you much when Orit wants to make an account for herself.

How about passing in the username as an argument right from the start, like a method, when creating the new User object?

orit = User.new("supermom")

To do this, you’ll need to modify your User class so that it can accept arguments. It may be tempting to do something like this:

class User(username)  # ...end

But as you’ll quickly encounter, this will throw an error. This is a completely reasonable assumption, though.

Instead, you can include the argument as a part of the initialize method.

A good way to remember this is to keep in mind that initialize takes care of everything related to the initial set-up of an object.

Since the username argument deals with the initial set-up of a username, it belongs to the initialize method.

class User  attr_accessor :username  def initialize(username)    @username = username  endend

Now you can initialize a User object with a username right when you create it.

orit = User.new("supermom")# => #
orit.username# => "supermom"

This also safeguards you from creating a new user without a username.

mike = User.new# ArgumentError: wrong number of arguments (0 for 1)

If you break apart that error, it shouldn’t be too tough to figure out what the issue is.

  • ArgumentError: This probably has something to do with the arguments passed into thisUser object.
  • wrong number of arguments (0 for 1): Zero arguments were passed in, when theUser class is expecting one.

Errors can seem scary, but often they contain vital information to help fix bugs in your code. Good error messages will tell you exactly where you need to make a fix.

 

 

转载于:https://www.cnblogs.com/iwangzheng/p/5450462.html

你可能感兴趣的文章
lunix的查看Tomcat目录下日志的快速操作
查看>>
zabbix添加邮件报警机制
查看>>
微信开放之模板消息
查看>>
Hql 中实用查询时候 引号的使用
查看>>
利用PowerShell复制SQLServer账户的所有权限
查看>>
SQLServer 维护脚本分享(10)索引
查看>>
js里父页面与子页面的相互调用
查看>>
AES加解密【示例】
查看>>
jdbc向各种数据库发送sql语句
查看>>
比特币进一步学习-针对作弊问题的处理
查看>>
Android实现手机摄像头的自动对焦
查看>>
ASCII流程图
查看>>
Linux知识积累(5) 关机shutdown和重启reboot
查看>>
HTML5为输入框添加语音输入功能
查看>>
[LeetCode] Find Permutation 找全排列
查看>>
os.environ() 说明
查看>>
Python学习札记(二十) 函数式编程1 介绍 高阶函数介绍
查看>>
tomcat安装不成功.提示:failed to install tomcat6 service ,check your setting and permissions
查看>>
[转]当当网高可用架构之道--转
查看>>
ROS学习网址【原创】
查看>>