ruby学习笔记

本文是作者在学习Ruby过程中整理的笔记,重点讨论了Ruby中的类变量和实例变量的使用、访问控制机制,包括父类私有方法的继承、封装的概念,以及`freeze`方法的应用和常量的特性。通过实例代码解析了Ruby语言的这些核心概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

微信搜索我吃你家米了关注公众号

在这里插入图片描述

该文章主要是用于记录在Ruby学习过程中遇到的一些疑难点

Ruby中的类变量和实例变量

参考文章

两者在形式上的区别就是,类变量使用@@标识,实例变量使用@标识

使用中的区别参考以下代码

class Test
  @@class_var = 10
  @class_instance_var  = "234234234"
  #类方法: 两种变量都可以访问
  def self.outclass_var
      puts @@class_var
  end
  def self.outclass_instance_var
      puts @class_instance_var
  end
  #类实例方法: 不能访问类实例变量
  def outclass_var
	  puts @@class_var
  end
  def outclass_instance_var
      puts @class_instance_var
  end
end

m = Test.new
m.outclass_var
m.outclass_instance_var
Test.outclass_instance_var

输出如下:

10

234234234

从输出结果可以看出outclass_instance_var方法被调用后并没有任何输出,原因是实例变量是无法被实例方法访问的,只能被类方法访问,只有出现在initialize方法中的实例变量才能被实例方法访问

且实例变量是无法被子类继承的,类变量可以被继承

class Dog  
  def initialize(breed)  
    @breed = breed  
  end  
end  
  
class Lab < Dog  
  def initialize(breed, name)  
    super(breed)  
    @name = name  
  end  
  
  def to_s  
    "(#@breed, #@name)"  
  end  
end  
  
puts Lab.new("Labrador", "Benzy").to_s  

输出结果:

(Labrador, Benzy)

可以看到子类调用了父类的initialize方法,父类的initialize@breed这个实例变量进行了赋值,导致该实例变量扩展到了子类中,之所以会这样是因为虽然实例变量和继承机制无关,但是父类的方法是会被继承的,那么被继承的方法所创建出来的变量就会扩展到子类中

# p049instvarinherit.rb  
class C  
  def initialize  
    @n = 100  
  end  
  
  def increase_n  
    @n *= 20  
  end  
end  
  
class D < C  
  def show_n  
    puts "n is #{@n}"  
  end  
end  
  
d = D.new  
d.increase_n  
d.show_n  

该代码输出结果是2000,这说明了子类对象也拥有了实例变量@n

如果在子类中定义了和父类相同的实例变量,那么子类中的实例变量的值会直接覆盖父类变量

加深对ruby的类变量的理解,看下面一段代码:

# variables and methods start lowercase  
$glob = 5             # global variables start with $  
class TestVar         # class name constant, start uppercase  
 @@cla = 6            # class variables start with @@  
 CONST_VAL = 7        # constant style, all caps, underscore  
 def initialize(x)    # constructor  
  @inst = x           # instance variables start with @  
  @@cla += 1          # each object shares @@cla  
 end  
 def self.cla         # class method, getter  
  @@cla  
 end  
 def self.cla=(y)     # class method, setter, also TestVar.  
  @@cla = y  
 end  
 def inst             # instance method, getter  
  @inst  
 end  
 def inst=(i)         # instance method, setter  
  @inst = i  
 end  
end  
puts $glob  
test = TestVar.new(3) # calls constructor  
puts TestVar.cla      # calls getter  
puts test.inspect     # gives object ID and instance vars  
TestVar.cla = 4       # calls setter  
test.inst=8           # calls setter  
puts TestVar.cla  
puts test.inst        # calls getter  
other = TestVar.new(17)
other = TestVar.new(18)  
other = TestVar.new(19)  
puts other.inspect  
puts TestVar.cla  

输出如下:

5
7
#<TestVar:0x000000000632a1f8 @inst=3>
4
8
#<TestVar:0x0000000006329f50 @inst=19>
7

可以看到,正如注释中所说,类变量是被每一个对象所共享的,我们每调用一次new@@cal类变量就会在initialize方法中+1,我们调用了3次new@@cal由4变成了7

ruby的访问控制

父类私有方法可以被子类继承

在ruby中,父类的私有方法是可以被子类继承的,但是一般情况下,私有方法是作为类内部的一些辅助方法,对类内部的一些功能可能起着至关重要的作用,所以子类在定义方法的时候注意不要和父类的私有方法相同,否则可能会造成父类私有方法重写的可能,这样在子类使用到这些私有方法的时候就可能会出现问题

封装

在访问控制方面,ruby和其他高级语言有着一些细微的区别,其中一点就是ruby定义的类中的成员变量是无法被外部对象直接访问的,也就是说他们全部都是私有的,要想让外部访问到这些变量,我们只能通过public修饰的gettersetter方法来进行访问,在ruby中,这两个方法被称为attribute readerattribute writer

# p048accessor.rb  
# First without accessor methods  
class Song  
  def initialize(name, artist)  
    @name     = name  
    @artist   = artist  
  end  
  def name  
    @name  
  end  
  def artist  
    @artist  
  end  
end  
  
song = Song.new("Brazil", "Ivete Sangalo")  
puts song.name  
puts song.artist  
  
# Now, with accessor methods  
class Song  
  def initialize(name, artist)  
    @name     = name  
    @artist   = artist  
  end  
  attr_reader :name, :artist  # create reader only  
  # For creating reader and writer methods  
  # attr_accessor :name  
  # For creating writer methods  
  # attr_writer :name  
  
end  
  
song = Song.new("Brazil", "Ivete Sangalo")  
puts song.name  
puts song.artist  

可以看到ruby有一个非常简洁的语法来直接定义attribute reader

attr_reader :name, :artist
这其实就是个语法糖,还有attr_writerattr_accessor

这样声明之后我们就可以直接使用外部对象去访问类中的私有变量了

ruby的freeze方法

该方法可以用来将对象变成immutable,也就是只读的,我们来观察下面两个例子

str = 'A simple string. '
str.freeze
begin
  str << 'An attempt to modify.'
rescue => err
  puts "#{err.class} #{err}"
end

输出结果如下:

FrozenError can't modify frozen String: "A simple string. "

可以看到,当我们试图往只读对象str上附加字符串时,出现报错,报错类型为FrozenError

再看另一段代码:

str = 'Original string - '
str.freeze
str += 'attachment'
puts str

输出结果如下:

Original string - attachment

可以看到,这段代码成功运行了,并且str的值改变了

原因就在于<<+=这两个操作符的区别,前者不会改变str所指向的对象,但是后者却会改变str所指向的对象,可以看如下代码:

str = 'Original string - '
puts "Before:: #{str.object_id}"
str.freeze
str += 'attachment'
puts "After:: #{str.object_id}"
puts str

输出结果如下:

Before:: 60
After:: 80
Original string - attachment

ruby中的常量

A_CONST = "Doshi"
A_CONST = "Joshi"  
puts A_CONST
puts "\n--------------------\n\n"
B_CONST = "Doshi"
B_CONST[0] = "J"
puts B_CONST

输出结果:

C:/Users/19856/p062stuff.rb:2: warning: already initialized constant A_CONST
C:/Users/19856/p062stuff.rb:1: warning: previous definition of A_CONST was here
Joshi

--------------------

Joshi

可以看到,使用第一种方式直接修改常量的值,虽然修改成功了,但是爆出了warning,然而使用第二种方式却可以完美地更改常量的值

在这里插入图片描述

主要是因为,第二种更改方式是通过更改对象的内部状态来达到修改的目的的,可以看到代码中使用的是数组的形式B_CONST[0] = "J"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值