红袖添香,绝代妖娆,Ruby语言基础入门教程之Ruby3基础数据类型(data types)EP02
Ruby是强类型动态语言,即Ruby中一旦某一个对象被定义类型,如果不通过强制转换操作,那么它永远就是该数据类型,并且只有在Ruby解释器运行时才会检测对象数据类型,它的一切皆为对象(包括 nil 值对象),可以通过调用内置class属性来获取该对象的具体数据类型。对于 Ruby 而言,所有类型都继承自 Object 类(根类为 BasicObject)。
数字(Numeric)
数字是最基本的数据类型之一,Ruby 中包含五种内置数字类型类: Numeric, Integer, Float, Fixnum 和 Bignum, 另外标准库中还提供了三种数字类型:Complex, BigDecimal, Rational. 除 Numeric 类外其他数字类型类都继承自 Numeric。
irb(main):005:0> 100.class
=> Integer
irb(main):004:0> Integer.superclass
=> Numeric
31位以内的整数为 Fixnum, 超过31位的数为Bignum, Bignum 没有位数限制,可以理解为长整形。
Ruby3支持基本的数学运算符(+, -, *, /),及取余(%), 求指数(**),等。
所有数字对象为不可变对象,因此 Ruby中没有自增和自减操作符(++, –):
irb(main):006:0> x = 4/2
=> 2
irb(main):007:0> y = 6.0/2
=> 3.0
irb(main):008:0> x**2
=> 4
irb(main):009:0> x**-1
=> (1/2)
irb(main):010:0> x**(1/2.0)
irb(main):011:0> x**(1/3)
=> 1
irb(main):012:0> x
=> 2
在Ruby中,一元运算符+=、 -=、 *=等其它类似的操作,和对应的二元运算x = x + y是完全等价的,都会创建新的对象x。其它语言中,可能一元操作符是原处修改的,对应的二元运算是非原处修改的,所以其它语言中使用一元运算方式效率可能会稍高一些,但Ruby中是等价的,所以说变了,一元运算符在Ruby中的作用仅仅是减少代码量,而并非有性能优化的空间。
对于浮点数来讲,Ruby提供了BigDecimal类来解决精度丢失问题,使用该类可以按实际值运算,但效率上不占优势:
irb(main):013:0> require 'bigdecimal'
irb(main):014:0> BigDecimal('0.2') - BigDecimal('0.1') === BigDecimal('0.1')
=> true
字符串(String)
普通字符串对象通常以双引号的形式声明,可转义字符,单引号原样输出不转义,字符串还可以包含变量或表达式(内嵌 #{ expr }):
irb(main):017:0> "360 degrees = #{2*Math::PI} radians"
=> "360 degrees = 6.283185307179586 radians"
注意#{ expr }方式需要双引号引用。
也像Python那样可以使用类似通配符的方式格式化输出:
irb(main):022:0> "%s: %f" % ["pi", Math::PI]
=> "pi: 3.141593"
和其他语言不同的是,Ruby3中的字符串是可变对象:
irb(main):028:0> ss = "123"
=> "123"
irb(main):029:0> ss[0]
=> "1"
irb(main):030:0> ss[0] = "2"
=> "2"
irb(main):031:0> ss
=> "223"
也就是说,如果我们定义了一个字符串,可以随时通过下标对字符串中的字符进行修改,而Python或者Golang中的字符串是不可变对象,所以只能通过重新赋值的方式进行修改。
常用的字符串方法:
# 获取字符串长度
"Hello".length #=> 5
"Hello World!".length #=> 12
# 判断字符串是否为空
"Hello".empty? #=> false
"!".empty? #=> false
" ".empty? #=> false
"".empty? #=> true
# 检索字符数量
"HELLO".count('L') #=> 2
"HELLO WORLD!".count('LO') #=> 1
# 插入字符串
"Hello".insert(3, "hi5") #=> Helhi5lo # "hi5" is inserted into the string right before the second 'l' which is at index 3
# 转大写
"Hello".upcase #=> HELLO
# 转小写
"Hello".downcase #=> hello
# 交换大小写
"hELLO wORLD".swapcase #=> Hello World
# 字符串翻转
"Hello World!".reverse #=> "!dlroW olleH"
# 字符串切割数组
"Hello, how are you?".split #=> ["Hello,", "how", "are", "you?"]
# 字符删除
name = "Batman"
name.chop
name == "Batma" #=> false
# 清除空格
" Hello ".strip #=> Hello
# 强转整形
"15".to_i #=> 15 # integer
# 字符串拼接
"15" + "15" #=> "1515" # string
"15" << "15" #=> "1515" # string
"15".concat "15" #=> "1515" # string
# 获取字符索引
"information".index('o') #=> 3
"information".index('mat') #=> 5
"information".index(/[abc]/) #=> 6
"information".index('o', 5) #=> 9
"information".index('z') #=> nil
可以看到,全部由字符串内置属性完成,并不需要外部方法的参与。
与此同时,还可以通过对象的的frozen?属性判断类型是否可变。
irb(main):035:0> "123".frozen?
=> false
irb(main):036:0> 3.frozen?
=> true
返回true为不可变对象,而false则代表可变。
符号(symbol)
符号(symbol)和字符串很相似,符号也是对象,一般作为名称标签来使用,用来表示变量等对象的名称,另外符号和字符串可以相互转换。
声明符号:
#声明symbol对象
:test1
:'test'
其实就是字符串前面加个冒号: 就是符号。
字符串和符号区别:
#可以通过object_id方法来获得一个对象的标识符
'test1'.object_id
=>70201737198340
'test1'.object_id
=>70201752605900
'test1'.object_id
=>70201752351880
:test2.object_id
=>8869148
:test2.object_id
=>8869148
:'test2'.object_id
=>8869148
在Ruby3中每一个对象都有唯一对象标识符,也可以理解为内存地址标识,每个字符串对象都是不同的,即使它们包含了相同的字符串内容,而对于符号对象,相同的字符串内容则只会指向唯一确定的一个符号对象,这样实际上节约了内存,减少了性能损耗。
符号不可以像其他变量一样对它进行赋值运算。比如这样的写法是错误的:myname = "test"。 相反符号可以作为值赋给其他变量比如mystring = :myname。
所有符号对象存放在 Ruby内部的符号表中,可以通过类方法 Symbol.all_symbols 得到当前 Ruby 程序中定义的所有 Symbol 对象,该方法返回一个 Symbol 对象数组。
符号与字符串相互转换:
var1 = "test".to_sym #=>:test
var1 = :test.to_s #=>"test"
一般情况下,符号作为哈希的key进行取值操作,这样效率和性能更高:
H = Hash[:"a" => 100, :"b" => 200]
puts H[:a]
程序返回:
100
因为 Ruby3对每一次字符串引用都会生成一个字符串对象,累积下来这个开销是相当大的。
需要注意的是,符号是不可变对象。
哈希(Hash)
哈希是一种非常有用且广泛使用的复合容器对象,可用于存储其他对象。我们通过键(key)来查找哈希中的值(value)。好比我们有一个牛津词典,我们通过查找“hello的单词来找到中文意思"你好",此时,“hello“就是作为键,而“你好”就是值。
声明哈希:
H = {}
可以单独对key和value进行赋值操作:
H[:a] = "123"
puts H[:a]
也可以通过使用=>将键分配给值来创建哈希,用逗号分隔多个键值对,并用花括号将整个内容括起来:
H = { "one" => "1", "two" => "2", "three" => "3" }
puts H
直接通过key就可以进行取值、修改等操作:
puts H["one"]
当我们查找的键没有对应内容时,会返回一个nil。
也可以使用fetch方法,他和[]方法一样都可以查找某一个键的值,但是如果键对应的值不存在,会抛出异常。
哈希可以进行合并操作:
a = { "one" => "eins" }
b = { "two" => "zwei" }
puts a.merge(b)
puts a
通过keys方法打印所有的键:
H = {}
H[:a] = "123"
puts H.keys()
也可以通过values返回一个带有哈希所有值的数组:
H = {}
H[:a] = "123"
H["123"] = "123"
puts H.values()
判断哈希是否为空:
{}.empty?
# ---- 输出结果 ----
true
也可以使用size或者length方法,判断哈希的大小是否为0:
dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
puts dictionary.size == 0
puts dictionary.length == 0
# ---- 输出结果 ----
false
false
通过delete方法删除键值对:
dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
dictionary.delete("one")
puts dictionary
# ---- 输出结果 ----
{"two"=>"zwei", "three"=>"drei"}
需要注意的是,哈希是可变对象:
irb(main):041:0> {}.frozen?
=> false
数组(Array)
数组是一个包含许多元素的对象。这些元素可以是变量(例如 字符串,数字,哈希等),甚至可以是其他对象(包括构成多维数组的其他数组)。定义中索引指的是数组元素中的一个序号,它从0开始,每个索引对应一个元素。说白了,就是一个内部元素内存地址连续的线性结构。
声明数组:
A = []
创建字符串数组:
> %w{ cat dog monkey }
=> ["cat", "dog", "monkey"]
创建符号数组:
> %i{ cat dog monkey }
=> [:cat, :dog, :monkey]
判断数组是否为空:
# 定义一个空数组
> days_of_week = []
=> []
days_of_week.empty?
=> true
也可以使用length或者size:
> days_of_week.length == 0
=> true
> days_of_week.size == 0
=> true
通过索引访问数组元素:
# 定义一个数组
> days_of_week = [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]
=> [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]
> days_of_week[0]
=> "Mon"
> days_of_week[1]
=> "Tues"
使用数组的first和last方法访问首个和末尾元素:
> days_of_week.first
=> "Mon"
> days_of_week.last
=> "Sun"
通过index返回元素下标:
# 定义一个数组
> days_of_week = [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]
=> [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]
> days_of_week.index("Wed")
=> 2
提取子元素:
# 定义一个数组
> days_of_week = [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]
=> [ "Mon", "Tues", "Wed", "Thu", "Fri", "Sat", "Sun" ]
> days_of_week[1, 3]
=> ["Tues", "Wed", "Thu"]
也可以针对数组指定范围:
> days_of_week[1..3]
=> ["Tues", "Wed", "Thu"]
合并数组:
days1 = ["Mon", "Tue", "Wed"]
days2 = ["Thu", "Fri", "Sat", "Sun"]
days = days1 + days2
=> ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
使用<<将元素动态附加到现有数组:
days1 = ["Mon", "Tue", "Wed"]
days1 << "Thu" << "Fri" << "Sat" << "Sun"
=> ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
数组的交集 &:
operating_systems = ["Fedora", "SuSE", "RHEL", "Windows", "MacOS"]
linux_systems = ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora"]
operating_systems & linux_systems
=> ["Fedora", "SuSE", "RHEL"]
数组的差集 -
operating_systems = ["Fedora", "SuSE", "RHEL", "Windows", "MacOS"]
linux_systems = ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora"]
operating_systems - linux_systems
linux_systems - operating_systems
数组的并集 |
operating_systems = ["Fedora", "SuSE", "RHEL", "Windows", "MacOS"]
linux_systems = ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora"]
operating_systems | linux_systems
=> ["Fedora", "SuSE", "RHEL", "Windows", "MacOS", "PCLinuxOS", "Ubuntu"]
数组删除重复元素:
linux_systems = ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora", "RHEL", "SuSE"]
linux_systems.uniq
=> ["RHEL", "SuSE", "PCLinuxOS", "Ubuntu", "Fedora"]
向数组中增加或减少元素(push和pop)
colors = ["red", "green", "blue"]
=> ["red", "green", "blue"]
colors.push "indigo"
=> ["red", "green", "blue", "indigo"]
colors.push "violet"
=> ["red", "green", "blue", "indigo", "violet"]
colors.pop
=> "violet"
colors.pop
=> "indigo"
基于先进后出原则。
数组插入元素:
colors = ["red", "green", "blue"]
=> ["red", "green", "blue"]
colors.insert( 1, "orange" )
=> ["red", "orange", "green", "blue"]
基于下标来删除元素:
colors = ["red", "green", "blue"]
=> ["red", "green", "blue"]
colors.delete_at(1)
=> "green"
colors
=> ["red", "blue"]
基于元素内容来删除:
colors = ["red", "green", "blue"]
=> ["red", "green", "blue"]
colors.delete("red")
=> "red"
colors
=> ["green", "blue"]
最后是排序:
numbers = [1, 4, 6, 7, 3, 2, 5]
=> [1, 4, 6, 7, 3, 2, 5]
numbers.sort
=> [1, 2, 3, 4, 5, 6, 7]
布尔和Nil
true 和 false 为两个布尔型的值,与其他语言理解有差别的是,除了 false 和 nil 外,其他值都为 true:
!true # false
!false # true
!nil # true
!0 # false
![] # false
nil 表示空值对象。对于值判空操作可调用 nil? 方法:
false.nil? # false
nil.nil? # true
需要注意的是,Ruby3中的nil是一个对象,表示没有任何东西的对象,而不是没有对象。nil与nil的比较无论是==还是eql?都返回true。
结语
字符、数字、布尔是不可变对象,而字符串、数组、哈希是可变对象,Ruby3中所有不可变对象的多个同值对象,都会指向同一个对象的内存地址。例如所有的1数值都是同一个对象,所有的nil、布尔值相同的字符对象也都是指向同一个对象,这也导致了Ruby3中不支持++或者--这样的操作,因为这要求在内存地址中指向的原对象进行增减操作,造成对象引用混乱的现象。
红袖添香,绝代妖娆,Ruby语言基础入门教程之Ruby3基础数据类型(data types)EP02的更多相关文章
- HealthKit开发快速入门教程之HealthKit数据的操作
HealthKit开发快速入门教程之HealthKit数据的操作 数据的表示 在HealthKit中,数据是最核心的元素.通过分析数据,人们可以看到相关的健康信息.例如,通过统计步数数据,人们可以知道 ...
- HealthKit开发快速入门教程之HealthKit框架体系创建健康AppID
HealthKit开发快速入门教程之HealthKit框架体系创建健康AppID HealthKit开发准备工作 在开发一款HealthKit应用程序时,首先需要讲解HealthKit中有哪些类,在i ...
- HealthKit开发快速入门教程之HealthKit开发概述简介
HealthKit开发快速入门教程之HealthKit开发概述简介 2014年6月2日召开的年度开发者大会上,苹果发布了一款新的移动应用平台,可以收集和分析用户的健康数据.该移动应用平台被命名为“He ...
- Nmap扫描教程之Nmap基础知识
Nmap扫描教程之Nmap基础知识 Nmap扫描Nmap基础知识 Nmap是一个免费开放的网络扫描和嗅探工具包,也叫网络映射器(Network Mapper).Nmap工具可以用来扫描电脑上开放的端口 ...
- nodejs入门教程之http的get和request简介及应用
nodejs入门教程之http的get和request简介及应用 前言 上一篇文章,我介绍了nodejs的几个常用的模块及简单的案例,今天我们再来重点看一下nodejs的http模块,关于http模块 ...
- github 入门教程之 github 访问速度太慢怎么办
github 是全世界最流行的开源项目托管平台,其代表的开源文化从根本上改变了软件开发的方式. 基本上所有的需求都能从 github 上或多或少找到现成的实现方案,再也不用重头开始造轮子而是自定义轮子 ...
- C++入门教程之二:变量
C++入门教程之二:变量 变量,顾名思义,意思是变化的量.变量的定义是计算机语言中能储存计算结果或能表示值的抽象概念.一个基本的程序需要变量,因此变量是程序设计中的一大重点. 变量基本结构 var_t ...
- javascript基础入门之js中的数据类型与数据转换01
javascript基础入门之js中的数据结构与数据转换01 js的组成(ECMAScript.BOM.DOM) js中的打印语句: 数据类型 变量 ...
- python基础入门一(语法基础)
作为自己正式接触并应用的第一门编程语言,在Alex和武sir两位大王的要求下,开始了写博客总结的日子.学习编程语言是很有趣的一件事情,但有2点请一定要谨记:1.做人靠自己,码代码也必须靠自己.能不能成 ...
- 🚴♂️全套MySQL数据库教程_Mysql基础入门教程,零基础小白自学MySQL数据库必备教程☔ #002 # 第二单元 MySQL数据类型、操作表#
二.本单元知识点概述 (Ⅰ)知识点概述 二.本单元教学目标 (Ⅰ)重点知识目标 1.Mysql的数据类型2.如何选择数据类型3.创建表4.修改表5.删除表 (Ⅱ)能力目标 1.熟练创建数据库及删除数据 ...
随机推荐
- 【前端必会】走进webpack生命周期,另类的学习方法
背景 webpack构建过程中的hooks都有什么呢?除了在网上看一些文章,还可以通过更直接的办法,结合官方文档快速让你进入webpack的hook世界 写一个入口文件 //index.js cons ...
- java.lang.ClassNotFoundException:(新建的servlet无法找到class文件)的报错
该问题有可能是IDEA的部署没有更新的问题 将out中的 删除,然后重新导入即可
- 后端框架的学习----mybatis框架(8、lombok)
8.lombok #测试环境搭建 1.导入lombok 2.新建实体类Teacher,Student 3.建立mapper接口 4.建立mapper.xml文件 5.在核心配置文件中绑定注册mappe ...
- IDEA中如何导入jar包、IDEA中找不到对应类改怎样解决?(详细图解过程)
今天突然心血来潮.用IDEA运行之前用eclipse编写的项目.发现遇到了一些bug,现在习惯了使用maven管理项目的依赖.一时间忘记了怎样将jar包导入项目中.特此记录一下 文章目录 1.未加入j ...
- 虚拟机安装Linux系统的网络配置
1. 进入配置文件配置.如果不知道ifcfg 后的内容.使用ifconfig vi /etc/sysconfig/network-scripts/ifcfg-ens33 如果不知道网关怎样配置就找到这 ...
- .Net Core&RabbitMQ限制循环消费
前言 当消费者端接收消息处理业务时,如果出现异常或是拒收消息将消息又变更为等待投递再次推送给消费者,这样一来,则形成循环的条件. 循环场景 生产者发送100条消息到RabbitMQ中,消费者设定读取到 ...
- 云原生之旅 - 6)不能错过的一款 Kubernetes 应用编排管理神器 Kustomize
前言 相信经过前一篇文章的学习,大家已经对Helm有所了解,本篇文章介绍另一款工具 Kustomize,为什么Helm如此流行,还会出现 Kustomize?而且 Kustomize 自 kubect ...
- 前端学习笔记--HTML5
网页的优点(客户端为网页)(B/S)模式 开发成本低) 不需要安装 无需更新 跨平台(最重要)可以有效的减小开发成本 传统的为C/S模式,开发成本高 前端工程师负责写网页的源代码,而浏览器负责把网页渲 ...
- 安装nvm 和 yarn
安装nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 执行上面的命令 如果出现问题 ...
- Go语言核心36讲45
你好,我是郝林,我今天继续分享bufio包中的数据类型. 在上一篇文章中,我提到了bufio包中的数据类型主要有Reader.Scanner.Writer和ReadWriter.并着重讲到了bufio ...