ruby 新建对象
by Nishant Mishra
由Nishant Mishra
Ruby面向对象编程简介 (An Introduction to Object-Oriented Programming with Ruby)
As a computer science student, I spend a lot of time learning and playing with new languages. Every new language has something unique to offer. Having said that, most beginners start off their programming journey with either procedural languages like C or with object-oriented languages like JavaScript and C++.
作为计算机科学专业的学生,我花了大量时间学习和使用新语言。 每种新语言都有其独特之处。 话虽如此,大多数初学者都是从程序语言(如C)或面向对象的语言(如JavaScript和C ++)开始编程的。
Therefore, it makes sense to go through the basics of object-oriented programming so you can understand the concepts and apply them to the languages you learn easily. We’ll be using the Ruby programming language as an example.
因此,通读面向对象编程的基础知识是有意义的,这样您就可以理解这些概念并将其应用于容易学习的语言。 我们将以Ruby编程语言为例。
You may be asking, why Ruby? Because it is “designed to make programmers happy” and also because almost everything in Ruby is an object.
您可能会问,为什么要使用Ruby? 因为它“旨在使程序员感到高兴”,而且因为Ruby中的几乎所有东西都是对象。
了解面向对象范例(OOP) (Getting a sense of the Object-Oriented Paradigm (OOP))
In OOP, we identify the “things” that our program handles. As humans, we think about things as objects with attributes and behaviors, and we interact with things based on these attributes and behaviors. A thing can be a car, a book, and so on. Such things become classes (the blueprints of objects), and we create objects out of these classes.
在OOP中,我们确定程序处理的“事物”。 作为人类,我们将事物视为具有属性和行为的对象,并基于这些属性和行为与事物进行交互。 事物可以是汽车,书籍等。 这样的东西变成了类(对象的蓝图),我们从这些类中创建了对象。
Each instance (object) contains instance variables which are the state of the object (attributes). Object behaviors are represented by methods.
每个实例(对象)包含实例变量,这些变量是对象(属性)的状态。 对象行为由方法表示。
Let’s take the example of a car. A car is a thing which would make it a class. A specific type of car, say BMW is an object of the class Car. The attributes/properties of a BMW such as the color and model number can be stored in instance variables. And if you want to perform an operation of the object, such as driving, then “drive” describes a behavior which is defined as a method.
让我们以汽车为例。 汽车是一种使它成为阶级的东西。 宝马(BMW)是一种特殊类型的汽车,是Car类的对象 。 BMW的属性/属性 (例如颜色和型号)可以存储在实例变量中。 并且,如果要执行对象的操作(例如驱动),则“驱动”描述了一种定义为方法的行为。
快速语法课 (A Quick Syntax Lesson)
- To end a line in a Ruby program, a semicolon(;) is optional (but is generally not used) 要在Ruby程序中结束一行,分号(;)是可选的(但通常不使用)
- 2-space indentation for each nested level is encouraged (not required, like it is in Python) 鼓励为每个嵌套级别使用2个空格的缩进(不是必需的,就像在Python中一样)
No curly braces
{}
are used, and the end keyword is used to mark the end of a flow control block不使用花括号
{}
,并且使用end关键字标记流控制块的结尾To comment, we use the
#
symbol要发表评论,我们使用
#
符号
The way objects are created in Ruby is by calling a new method on a class, as in the example below:
在Ruby中创建对象的方式是通过在类上调用新方法,如以下示例所示:
class Car def initialize(name, color) @name = name @color = color end
def get_info "Name: #{@name}, and Color: #{@color}" endend
my_car = Car.new("Fiat", "Red")puts my_car.get_info
To understand what’s going on in the code above:
要了解上面的代码中发生了什么:
We have a class named
Car
with two methods,initialize
andget_info
.我们有一个名为
Car
的类,具有两个方法,initialize
和get_info
。Instance variables in Ruby begin with
@
(For example@name
). The interesting part is that the variables are not initially declared. They spring into existence when first used, and after that they are available to all instance methods of the class.Ruby中的实例变量以
@
开头(例如@name
)。 有趣的是,变量最初并未声明。 它们在首次使用时就存在,然后可用于该类的所有实例方法。Calling the
new
method causes theinitialize
method to invoke.initialize
is a special method which is used as a constructor.调用
new
方法将导致initialize
方法被调用。initialize
是一种特殊的方法,用作构造函数。
存取资料 (Accessing Data)
Instance variables are private and can’t be accessed from outside the class. In order to access them, we need to create methods. Instance methods have public access by default. We can limit the access to these instance methods as we will see later in this article.
实例变量是私有的,不能从类外部访问。 为了访问它们,我们需要创建方法。 实例方法默认情况下具有公共访问权限。 我们可以限制对这些实例方法的访问,我们将在本文后面看到。
In order to get and modify the data, we need “getter” and “setter” methods, respectively. Let’s look at these methods taking the same example of a car.
为了获取和修改数据,我们分别需要“ getter”和“ setter”方法。 让我们以汽车为例来看看这些方法。
class Car def initialize(name, color) # "Constructor" @name = name @color = color end
def color @color end
def color= (new_color) @color = new_color endend
my_car = Car.new("Fiat", "Red")puts my_car.color # Red
my_car.color = "White"puts my_car.color # White
In Ruby, the “getter” and the “setter” are defined with the same name as the instance variable that we are dealing with.
在Ruby中,“ getter”和“ setter”的定义与我们要处理的实例变量的名称相同。
In the example above, when we say my_car.color
, it actually calls the color
method which in turn returns the name of the color.
在上面的示例中,当我们说my_car.color
,它实际上调用了color
方法,该方法又返回颜色的名称。
Note: Pay attention to how Ruby allows a space between the color
and equals to sign while using the setter, even though the method name is color=
注意: 使用方法时,即使方法名称为 color=
,也要 注意Ruby如何在 color
和equals 之间留出一个空格 以进行符号签名
Writing these getter/setter methods allow us to have more control. But most of the time, getting the existing value and setting a new value is simple. So, there should be an easier way instead of actually defining getter/setter methods.
编写这些getter / setter方法可以使我们拥有更多的控制权。 但是在大多数情况下,获取现有值并设置新值很简单。 因此,应该有一种比实际定义getter / setter方法更简单的方法。
更简单的方法 (The easier way)
By using the attr_*
form instead, we can get the existing value and set a new value.
通过使用attr_*
形式,我们可以获取现有值并设置一个新值。
attr_accessor
: for getter and setter bothattr_accessor
:用于getter和setter两者attr_reader
: for getter onlyattr_reader
:仅用于getterattr_writer
: for setter onlyattr_writer
:仅适用于二传手
Let’s look at this form taking the same example of a car.
让我们以汽车的相同示例来看一下这种形式。
class Car attr_accessor :name, :colorend
car1 = Car.newputs car1.name # => nil
car1.name = "Suzuki"car1.color = "Gray"puts car1.color # => Gray
car1.name = "Fiat"puts car1.name # => Fiat
This way we can skip the getter/setter definitions altogether.
这样,我们可以完全跳过getter / setter定义。
谈论最佳做法 (Talking about best practices)
In the example above, we didn’t initialize the values for the @name
and @color
instance variables, which is not a good practice. Also, as the instance variables are set to nil, the object car1
doesn’t make any sense. It’s always a good practice to set instance variables using a constructor as in the example below.
在上面的示例中,我们没有初始化@name
和@color
实例变量的值,这不是一个好习惯。 另外,由于实例变量设置为nil,所以对象car1
没有任何意义。 最好使用构造函数设置实例变量,如下例所示。
class Car attr_accessor :name, :color def initialize(name, color) @name = name @color = color endend
car1 = Car.new("Suzuki", "Gray")puts car1.color # => Gray
car1.name = "Fiat"puts car1.name # => Fiat
类方法和类变量 (Class Methods and Class Variables)
So class methods are invoked on a class, not on an instance of a class. These are similar to static methods in Java.
因此,类方法是在类上而不是在类的实例上调用的。 这些类似于Java中的静态方法。
Note: self
outside of the method definition refers to the class object. Class variables begin with @@
注意:方法定义之外的self
引用类对象。 类变量以@@
开头
Now, there are actually three ways to define class methods in Ruby:
现在,实际上有三种方法可以在Ruby中定义类方法:
在类定义内 (Inside the class definition)
- Using the keyword self with the name of the method: 将关键字self与方法名称一起使用:
class MathFunctions def self.two_times(num) num * 2 endend
# No instance createdputs MathFunctions.two_times(10) # => 20
2. Using <<
; self
2.使用<<
; 自
class MathFunctions class << self def two_times(num) num * 2 end endend
# No instance createdputs MathFunctions.two_times(10) # => 20
课外定义 (Outside the class definition)
3. Using class name with the method name
3.使用类名和方法名
class MathFunctionsend
def MathFunctions.two_times(num) num * 2end
# No instance createdputs MathFunctions.two_times(10) # => 20
类继承 (Class Inheritance)
In Ruby, every class implicitly inherits from the Object class. Let’s look at an example.
在Ruby中,每个类都隐式继承自Object类。 让我们来看一个例子。
class Car def to_s "Car" end
def speed "Top speed 100" endend
class SuperCar < Car def speed # Override "Top speed 200" endend
car = Car.newfast_car = SuperCar.new
puts "#{car}1 #{car.speed}" # => Car1 Top speed 100puts "#{fast_car}2 #{fast_car.speed}" # => Car2 Top speed 200
In the above example, the SuperCar
class overrides the speed
method which is inherited from the Car
class. The symbol &
lt; denotes inheritance.
在上面的示例中, SuperCar
类覆盖了从Car
类继承的speed
方法。 符号&
lt; 表示继承。
Note: Ruby doesn’t support multiple inheritance, and so mix-ins are used instead. We will discuss them later in this article.
注意:Ruby不支持多重继承,因此使用混入。 我们将在本文后面讨论它们。
Ruby中的模块 (Modules in Ruby)
A Ruby module is an important part of the Ruby programming language. It’s a major object-oriented feature of the language and supports multiple inheritance indirectly.
Ruby模块是Ruby编程语言的重要组成部分。 它是该语言的主要面向对象功能,并间接支持多重继承。
A module is a container for classes, methods, constants, or even other modules. Like a class, a module cannot be instantiated, but serves two main purposes:
模块是类,方法,常量甚至其他模块的容器。 像类一样,模块无法实例化,但是有两个主要目的:
- Namespace 命名空间
- Mix-in 混入
模块作为命名空间 (Modules as Namespace)
A lot of languages like Java have the idea of the package structure, just to avoid collision between two classes. Let’s look into an example to understand how it works.
许多语言(例如Java)都具有包结构的思想,只是为了避免两个类之间的冲突。 让我们看一个例子来了解它是如何工作的。
module Patterns class Match attr_accessor :matched endend
module Sports class Match attr_accessor :score endend
match1 = Patterns::Match.newmatch1.matched = "true"
match2 = Sports::Match.newmatch2.score = 210
In the example above, as we have two classes named Match
, we can differentiate between them and prevent collision by simply encapsulating them into different modules.
在上面的示例中,由于我们有两个名为Match
类,我们可以通过将它们封装到不同的模块中来区分它们并防止冲突。
模块作为混入 (Modules as Mix-in)
In the object-oriented paradigm, we have the concept of Interfaces. Mix-in provides a way to share code between multiple classes. Not only that, we can also include the built-in modules like Enumerable
and make our task much easier. Let’s see an example.
在面向对象的范例中,我们有接口的概念。 混合提供了一种在多个类之间共享代码的方法。 不仅如此,我们还可以包括诸如Enumerable
类的内置模块,使我们的工作更加轻松。 让我们来看一个例子。
module PrintName attr_accessor :name def print_it puts "Name: #{@name}" endend
class Person include PrintNameend
class Organization include PrintNameend
person = Person.newperson.name = "Nishant"puts person.print_it # => Name: Nishant
organization = Organization.neworganization.name = "freeCodeCamp"puts organization.print_it # => Name: freeCodeCamp
Mix-ins are extremely powerful, as we only write the code once and can then include them anywhere as required.
混合功能非常强大,因为我们只编写一次代码,然后可以根据需要在任何地方包含它们。
Ruby中的范围 (Scope in Ruby)
We will see how scope works for:
我们将看到范围如何工作:
- variables 变数
- constants 常数
- blocks 块
变量范围 (Scope of variables)
Methods and classes define a new scope for variables, and outer scope variables are not carried over to the inner scope. Let’s see what this means.
方法和类为变量定义了新的作用域,并且外部作用域变量不会继承到内部作用域。 让我们看看这意味着什么。
name = "Nishant"
class MyClass def my_fun name = "John" puts name # => John end
puts name # => Nishant
The outer name
variable and the inner name
variable are not the same. The outer name
variable doesn’t get carried over to the inner scope. That means if you try to print it in the inner scope without again defining it, an exception would be thrown — no such variable exists
外部name
变量和内部name
变量不同。 外部name
变量不会继承到内部范围。 这意味着,如果您尝试在内部范围中打印它而不再次定义它,则将引发异常- 不存在此类变量
常数范围 (Scope of constants)
An inner scope can see constants defined in the outer scope and can also override the outer constants. But it’s important to remember that even after overriding the constant value in the inner scope, the value in the outer scope remains unchanged. Let’s see it in action.
内部作用域可以看到在外部作用域中定义的常量,也可以覆盖外部常量。 但重要的是要记住,即使在覆盖内部作用域中的常量值之后,外部作用域中的值仍保持不变。 让我们来看看它的作用。
module MyModule PI = 3.14 class MyClass def value_of_pi puts PI # => 3.14 PI = "3.144444" puts PI # => 3.144444 end end puts PI # => 3.14end
块的范围 (Scope of blocks)
Blocks inherit the outer scope. Let’s understand it using a fantastic example I found on the internet.
块继承外部范围。 让我们用我在互联网上找到的一个很棒的例子来理解它。
class BankAccount attr_accessor :id, :amount def initialize(id, amount) @id = id @amount = amount endend
acct1 = BankAccount.new(213, 300)acct2 = BankAccount.new(22, 100)acct3 = BankAccount.new(222, 500)
accts = [acct1, acct2, acct3]
total_sum = 0accts.each do |eachAcct| total_sum = total_sum + eachAcct.amountend
puts total_sum # => 900
In the above example, if we use a method to calculate the total_sum
, the total_sum
variable would be a totally different variable inside the method. That’s why sometimes using blocks can save us a lot of time.
在上面的示例中,如果我们使用一种方法来计算total_sum
,则total_sum
变量将是该方法内部的完全不同的变量。 这就是为什么有时使用块可以节省大量时间的原因。
Having said that, a variable created inside the block is only available to the block.
话虽如此,在块内部创建的变量仅对块可用。
访问控制 (Access Control)
When designing a class, it is important to think about how much of it you’ll be exposing to the world. This is known as Encapsulation, and typically means hiding the internal representation of the object.
设计课程时,重要的是要考虑要向世界展示多少课程。 这就是所谓的封装,通常意味着隐藏对象的内部表示。
There are three levels of access control in Ruby:
Ruby中的访问控制分为三个级别:
Public - no access control is enforced. Anybody can call these methods.
公开 -不执行访问控制。 任何人都可以调用这些方法。
Protected - can be invoked by objects of the defining classes or its sub classes.
受保护的 -可以由定义类或其子类的对象调用。
Private - cannot be invoked except with an explicit receiver.
专用 -除非使用显式接收者,否则不能调用。
Let’s see an example of Encapsulation in action:
让我们看一个封装实际的例子:
class Car def initialize(speed, fuel_eco) @rating = speed * comfort end
def rating @rating endend
puts Car.new(100, 5).rating # => 500
Now, as the details of how the rating is calculated are kept inside the class, we can change it at any point in time without any other change. Also, we cannot set the rating from outside.
现在,由于如何计算评分的详细信息保留在班级内部,因此我们可以随时更改它,而无需进行其他任何更改。 另外,我们不能从外部设置等级。
Talking about the ways to specify access control, there are two of them:
谈到指定访问控制的方法,有两种:
- Specifying public, protected, or private and everything until the next access control keyword will have that access control level. 指定public,protected或private以及所有内容,直到下一个访问控制关键字将具有该访问控制级别。
- Define the method regularly, and then specify public, private, and protected access levels and list the comma(,) separated methods under those levels using method symbols. 定期定义方法,然后指定公共,私有和受保护的访问级别,并使用方法符号在这些级别下列出逗号分隔的方法。
第一种方式的示例: (Example of the first way:)
class MyClass private def func1 "private" end protected def func2 "protected" end public def func3 "Public" endend
第二种方式的示例: (Example of the second way:)
class MyClass def func1 "private" end def func2 "protected" end def func3 "Public" end private :func1 protected :func2 public :func3end
Note: The public and private access controls are used the most.
注意:最常使用公共和私人访问控制。
结论 (Conclusion)
These are the very basics of Object Oriented Programming in Ruby. Now, knowing these concepts you can go deeper and learn them by building cool stuff.
这些是Ruby中面向对象编程的基础知识。 现在,了解了这些概念后,您可以通过构建有趣的东西来更深入地学习它们。
Don’t forget to clap and follow if you enjoyed! Keep up with me here.
如果您喜欢的话,别忘了拍手并跟随! 在这里跟上我。
ruby 新建对象