找回密码
 立即注册
首页 资源区 代码 红袖添香,绝代妖娆,Ruby语言基础入门教程之Ruby3基础数 ...

红袖添香,绝代妖娆,Ruby语言基础入门教程之Ruby3基础数据类型(data types)EP02

曲愍糙 2025-6-4 20:09:09
Ruby是强类型动态语言,即Ruby中一旦某一个对象被定义类型,如果不通过强制转换操作,那么它永远就是该数据类型,并且只有在Ruby解释器运行时才会检测对象数据类型,它的一切皆为对象(包括 nil 值对象),可以通过调用内置class属性来获取该对象的具体数据类型。对于 Ruby 而言,所有类型都继承自 Object 类(根类为 BasicObject)。
数字(Numeric)

数字是最基本的数据类型之一,Ruby 中包含五种内置数字类型类: Numeric, Integer, Float, Fixnum 和 Bignum, 另外标准库中还提供了三种数字类型:Complex, BigDecimal, Rational. 除 Numeric 类外其他数字类型类都继承自 Numeric。
  1. irb(main):005:0> 100.class  
  2. => Integer
  3. irb(main):004:0> Integer.superclass  
  4. => Numeric
复制代码
31位以内的整数为 Fixnum, 超过31位的数为Bignum, Bignum 没有位数限制,可以理解为长整形。
Ruby3支持基本的数学运算符(+, -, *, /),及取余(%), 求指数(**),等。
所有数字对象为不可变对象,因此 Ruby中没有自增和自减操作符(++, –):
  1. irb(main):006:0> x = 4/2      
  2. => 2  
  3. irb(main):007:0> y = 6.0/2     
  4. => 3.0  
  5. irb(main):008:0> x**2        
  6. => 4  
  7. irb(main):009:0> x**-1         
  8. => (1/2)  
  9. irb(main):010:0> x**(1/2.0)   
  10. irb(main):011:0> x**(1/3)  
  11. => 1  
  12. irb(main):012:0> x  
  13. => 2
复制代码
在Ruby中,一元运算符+=、 -=、 *=等其它类似的操作,和对应的二元运算x = x + y是完全等价的,都会创建新的对象x。其它语言中,可能一元操作符是原处修改的,对应的二元运算是非原处修改的,所以其它语言中使用一元运算方式效率可能会稍高一些,但Ruby中是等价的,所以说变了,一元运算符在Ruby中的作用仅仅是减少代码量,而并非有性能优化的空间。
对于浮点数来讲,Ruby提供了BigDecimal类来解决精度丢失问题,使用该类可以按实际值运算,但效率上不占优势:
  1. irb(main):013:0> require 'bigdecimal'  
  2. irb(main):014:0> BigDecimal('0.2') - BigDecimal('0.1') === BigDecimal('0.1')  
  3. => true
复制代码
字符串(String)

普通字符串对象通常以双引号的形式声明,可转义字符,单引号原样输出不转义,字符串还可以包含变量或表达式(内嵌 #{ expr }):
  1. irb(main):017:0> "360 degrees = #{2*Math::PI} radians"  
  2. => "360 degrees = 6.283185307179586 radians"
复制代码
注意#{ expr }方式需要双引号引用。
也像Python那样可以使用类似通配符的方式格式化输出:
  1. irb(main):022:0> "%s: %f" % ["pi", Math::PI]  
  2. => "pi: 3.141593"
复制代码
和其他语言不同的是,Ruby3中的字符串是可变对象:
  1. irb(main):028:0> ss = "123"  
  2. => "123"  
  3. irb(main):029:0> ss[0]  
  4. => "1"  
  5. irb(main):030:0> ss[0] = "2"  
  6. => "2"  
  7. irb(main):031:0> ss  
  8. => "223"
复制代码
也就是说,如果我们定义了一个字符串,可以随时通过下标对字符串中的字符进行修改,而Python或者Golang中的字符串是不可变对象,所以只能通过重新赋值的方式进行修改。
常用的字符串方法:
  1. # 获取字符串长度  
  2. "Hello".length #=> 5  
  3. "Hello World!".length #=> 12  
  4.   
  5. # 判断字符串是否为空  
  6. "Hello".empty? #=> false  
  7. "!".empty?     #=> false  
  8. " ".empty?     #=> false  
  9. "".empty?      #=> true  
  10.   
  11. # 检索字符数量  
  12. "HELLO".count('L') #=> 2  
  13. "HELLO WORLD!".count('LO') #=> 1  
  14.   
  15. # 插入字符串  
  16. "Hello".insert(3, "hi5") #=> Helhi5lo # "hi5" is inserted into the string right before the second 'l' which is at index 3  
  17.   
  18. # 转大写  
  19. "Hello".upcase #=> HELLO  
  20.   
  21. # 转小写  
  22. "Hello".downcase #=> hello  
  23.   
  24. # 交换大小写  
  25. "hELLO wORLD".swapcase #=> Hello World  
  26.   
  27. # 字符串翻转  
  28. "Hello World!".reverse #=> "!dlroW olleH"  
  29.   
  30. # 字符串切割数组  
  31. "Hello, how are you?".split #=> ["Hello,", "how", "are", "you?"]  
  32.   
  33. # 字符删除  
  34. name = "Batman"  
  35. name.chop  
  36. name == "Batma" #=> false  
  37.   
  38. # 清除空格  
  39. "  Hello  ".strip #=> Hello  
  40.   
  41. # 强转整形  
  42. "15".to_i #=> 15 # integer  
  43.   
  44. # 字符串拼接  
  45.   
  46. "15" + "15" #=> "1515" # string  
  47.   
  48. "15" << "15" #=> "1515" # string  
  49.   
  50. "15".concat "15" #=> "1515" # string  
  51.   
  52. # 获取字符索引  
  53. "information".index('o') #=> 3  
  54. "information".index('mat') #=> 5  
  55. "information".index(/[abc]/) #=> 6  
  56. "information".index('o', 5) #=> 9  
  57. "information".index('z') #=> nil
复制代码
可以看到,全部由字符串内置属性完成,并不需要外部方法的参与。
与此同时,还可以通过对象的的frozen?属性判断类型是否可变。
  1. irb(main):035:0> "123".frozen?  
  2. => false  
  3. irb(main):036:0> 3.frozen?  
  4. => true
复制代码
返回true为不可变对象,而false则代表可变。
符号(symbol)

符号(symbol)和字符串很相似,符号也是对象,一般作为名称标签来使用,用来表示变量等对象的名称,另外符号和字符串可以相互转换。
声明符号:
  1. #声明symbol对象  
  2. :test1  
  3. :'test'
复制代码
其实就是字符串前面加个冒号: 就是符号。
字符串和符号区别:
  1. #可以通过object_id方法来获得一个对象的标识符  
  2. 'test1'.object_id  
  3. =>70201737198340   
  4. 'test1'.object_id  
  5. =>70201752605900  
  6. 'test1'.object_id  
  7. =>70201752351880   
  8.   
  9. :test2.object_id  
  10. =>8869148   
  11. :test2.object_id  
  12. =>8869148   
  13. :'test2'.object_id  
  14. =>8869148
复制代码
在Ruby3中每一个对象都有唯一对象标识符,也可以理解为内存地址标识,每个字符串对象都是不同的,即使它们包含了相同的字符串内容,而对于符号对象,相同的字符串内容则只会指向唯一确定的一个符号对象,这样实际上节约了内存,减少了性能损耗。
符号不可以像其他变量一样对它进行赋值运算。比如这样的写法是错误的:myname = "test"。 相反符号可以作为值赋给其他变量比如mystring = :myname。
所有符号对象存放在 Ruby内部的符号表中,可以通过类方法 Symbol.all_symbols 得到当前 Ruby 程序中定义的所有 Symbol 对象,该方法返回一个 Symbol 对象数组。
符号与字符串相互转换:
  1. var1 = "test".to_sym #=>:test  
  2.   
  3. var1 = :test.to_s #=>"test"
复制代码
一般情况下,符号作为哈希的key进行取值操作,这样效率和性能更高:
  1. H = Hash[:"a" => 100, :"b" => 200]  
  2. puts H[:a]
复制代码
程序返回:
  1. 100
复制代码
因为 Ruby3对每一次字符串引用都会生成一个字符串对象,累积下来这个开销是相当大的。
需要注意的是,符号是不可变对象。
哈希(Hash)

哈希是一种非常有用且广泛使用的复合容器对象,可用于存储其他对象。我们通过键(key)来查找哈希中的值(value)。好比我们有一个牛津词典,我们通过查找“hello的单词来找到中文意思"你好",此时,“hello“就是作为键,而“你好”就是值。
声明哈希:
  1. H = {}
复制代码
可以单独对key和value进行赋值操作:
  1. H[:a] = "123"  
  2.   
  3. puts H[:a]
复制代码
也可以通过使用=>将键分配给值来创建哈希,用逗号分隔多个键值对,并用花括号将整个内容括起来:
  1. H = { "one" => "1", "two" => "2", "three" => "3" }  
  2.   
  3. puts H
复制代码
直接通过key就可以进行取值、修改等操作:
  1. puts H["one"]
复制代码
当我们查找的键没有对应内容时,会返回一个nil。
也可以使用fetch方法,他和[]方法一样都可以查找某一个键的值,但是如果键对应的值不存在,会抛出异常。
哈希可以进行合并操作:
  1. a = { "one" => "eins" }  
  2. b = { "two" => "zwei" }  
  3. puts a.merge(b)  
  4. puts a
复制代码
通过keys方法打印所有的键:
  1. H = {}  
  2.   
  3. H[:a] = "123"  
  4.   
  5. puts H.keys()
复制代码
也可以通过values返回一个带有哈希所有值的数组:
  1. H = {}  
  2.   
  3. H[:a] = "123"  
  4.   
  5. H["123"] = "123"  
  6.   
  7. puts H.values()
复制代码
判断哈希是否为空:
  1. {}.empty?  
  2.   
  3. # ---- 输出结果 ----  
  4. true
复制代码
也可以使用size或者length方法,判断哈希的大小是否为0:
  1. dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }  
  2. puts dictionary.size == 0  
  3. puts dictionary.length == 0  
  4.   
  5. # ---- 输出结果 ----  
  6. false  
  7. false
复制代码
通过delete方法删除键值对:
  1. dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }  
  2. dictionary.delete("one")  
  3. puts dictionary  
  4.   
  5. # ---- 输出结果 ----  
  6. {"two"=>"zwei", "three"=>"drei"}
复制代码
需要注意的是,哈希是可变对象:
  1. irb(main):041:0> {}.frozen?  
  2. => false
复制代码
数组(Array)

数组是一个包含许多元素的对象。这些元素可以是变量(例如 字符串,数字,哈希等),甚至可以是其他对象(包括构成多维数组的其他数组)。定义中索引指的是数组元素中的一个序号,它从0开始,每个索引对应一个元素。说白了,就是一个内部元素内存地址连续的线性结构。
声明数组:
  1. A = []
复制代码
创建字符串数组:
  1. > %w{ cat dog monkey }  
  2. => ["cat", "dog", "monkey"]
复制代码
创建符号数组:
  1. > %i{ cat dog monkey }  
  2. => [:cat, :dog, :monkey]
复制代码
判断数组是否为空:
  1. # 定义一个空数组  
  2. > days_of_week = []  
  3. => []  
  4.   
  5. days_of_week.empty?  
  6. => true
复制代码
也可以使用length或者size:
  1. > days_of_week.length == 0  
  2. => true  
  3.   
  4. > days_of_week.size == 0  
  5. => true
复制代码
通过索引访问数组元素:
  1. # 定义一个数组  
  2. > days_of_week = [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]  
  3. => [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]  
  4.   
  5. > days_of_week[0]  
  6. => "Mon"  
  7.   
  8. > days_of_week[1]  
  9. => "Tues"
复制代码
使用数组的first和last方法访问首个和末尾元素:
  1. > days_of_week.first  
  2. => "Mon"  
  3.   
  4. > days_of_week.last  
  5. => "Sun"
复制代码
通过index返回元素下标:
  1. # 定义一个数组  
  2. > days_of_week = [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]  
  3. => [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]  
  4.   
  5. > days_of_week.index("Wed")  
  6. => 2
复制代码
提取子元素:
  1. # 定义一个数组  
  2. > days_of_week = [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]  
  3. => [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]  
  4.   
  5. > days_of_week[1, 3]  
  6. => ["Tues", "Wed", "Thu"]
复制代码
也可以针对数组指定范围:
  1. > days_of_week[1..3]  
  2. => ["Tues", "Wed", "Thu"]
复制代码
合并数组:
  1. days1 = ["Mon", "Tue", "Wed"]  
  2. days2 = ["Thu", "Fri", "Sat", "Sun"]  
  3. days = days1 + days2  
  4.   
  5. => ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
复制代码
使用 ["red", "green", "blue", "indigo"]    colors.push "violet"  => ["red", "green", "blue", "indigo", "violet"]    colors.pop  => "violet"    colors.pop  => "indigo"[/code]基于先进后出原则。
数组插入元素:
  1. days1 = ["Mon", "Tue", "Wed"]  
  2. days1 << "Thu" << "Fri" << "Sat" << "Sun"  
  3.   
  4. => ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
复制代码
基于下标来删除元素:
  1. operating_systems = ["Fedora", "SuSE", "RHEL", "Windows", "MacOS"]  
  2.   
  3. linux_systems = ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora"]  
  4.   
  5. operating_systems & linux_systems  
  6. => ["Fedora", "SuSE", "RHEL"]
复制代码
基于元素内容来删除:
  1. operating_systems = ["Fedora", "SuSE", "RHEL", "Windows", "MacOS"]  
  2.   
  3. linux_systems = ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora"]  
  4.   
  5. operating_systems  - linux_systems  
  6.   
  7. linux_systems - operating_systems
复制代码
最后是排序:
  1. operating_systems = ["Fedora", "SuSE", "RHEL", "Windows", "MacOS"]  
  2.   
  3. linux_systems = ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora"]  
  4.   
  5. operating_systems | linux_systems  
  6. => ["Fedora", "SuSE", "RHEL", "Windows", "MacOS", "PCLinuxOS", "Ubuntu"]
复制代码
布尔和Nil

true 和 false 为两个布尔型的值,与其他语言理解有差别的是,除了 false 和 nil 外,其他值都为 true:
  1. linux_systems = ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora", "RHEL", "SuSE"]  
  2.   
  3. linux_systems.uniq  
  4. => ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora"]
复制代码
nil 表示空值对象。对于值判空操作可调用 nil? 方法:
  1. colors = ["red", "green", "blue"]  
  2. => ["red", "green", "blue"]  
  3.   
  4. colors.push "indigo"  
  5. => ["red", "green", "blue", "indigo"]  
  6.   
  7. colors.push "violet"  
  8. => ["red", "green", "blue", "indigo", "violet"]  
  9.   
  10. colors.pop  
  11. => "violet"  
  12.   
  13. colors.pop  
  14. => "indigo"
复制代码
需要注意的是,Ruby3中的nil是一个对象,表示没有任何东西的对象,而不是没有对象。nil与nil的比较无论是==还是eql?都返回true。
结语

字符、数字、布尔是不可变对象,而字符串、数组、哈希是可变对象,Ruby3中所有不可变对象的多个同值对象,都会指向同一个对象的内存地址。例如所有的1数值都是同一个对象,所有的nil、布尔值相同的字符对象也都是指向同一个对象,这也导致了Ruby3中不支持++或者--这样的操作,因为这要求在内存地址中指向的原对象进行增减操作,造成对象引用混乱的现象。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册