网安
  • Develop
    • JAVA学习
      • 字节码
      • API开发
      • Web开发
      • 工程结构推荐
      • 创建第一个项目
      • 权限管控
      • 配置文件
      • 日志管理
      • 数据访问
      • 性能监控
      • IoC容器
      • Spring
      • Filter与Listener
      • jsp
      • MVC
      • servlet-1
      • servlet-2
      • servlet-3
      • servlet-4
      • FreeMarker
      • Thymeleaf
      • EL
      • SpEL
      • JSTL
      • 部署
      • JDBC
      • 数据库连接池
      • fastjson
      • jackson
      • XML
      • JSON
      • 序列化
      • Maven
      • 安装与使用
      • 工具
      • 爬虫
    • GO学习
      • GO
        • flag 包
        • goland 远程调试
        • GoReleaser
        • OS 包
        • time 包
        • 格式化输出
    • Lua学习
      • Lua
      • 基础语法
      • LuaJIT
      • 与系统交互
    • Pyhon
      • 基础
      • Django
      • CLI
      • miniforge
      • MockingBird
      • pdb
      • pyc
      • 装的我脑血栓要犯了
      • Python101
      • 反序列化
      • 爬虫
      • Pillow
      • 图像识别
      • flask
    • Speed-Ruby
      • 入门1
      • 入门2 对象
      • 入门3 创建命令
      • Encoding类
      • File类与Dir类
      • IO
      • Proc类
      • Time类与Date类
      • 正则
      • 错误处理与异常
      • 对象、变量和常量
      • 方法
      • 数值
      • 数组
      • 条件判断
      • 循环
      • 运算符
      • Socket编程
      • 字符串
      • 并发与线程
      • 块
      • 类和模块
      • 散列
    • Web
      • HTTP
        • Connection
        • HTTP 报文
        • Vary
      • 笔记
        • 跳转
        • 认证 & 授权
        • 同源策略(SOP)
        • 文件
    • Git 学习笔记
    • JSON
      • JSON 学习笔记
    • HTML
      • Speed-HTML
      • 语法学习
      • HTML字符实体
    • XML
      • XML 学习笔记
    • 计算机基础
      • 操作系统
      • 计算机组成
      • 算法
      • 内存
      • 字符编码
    • gnuplot 学习笔记
    • regex
  • Integrated
    • Linux
      • God-Linux
      • Secure-Linux
      • Power-Linux
      • IO模型
      • Speed-Linux
      • 发行版
      • 工具
      • 启动过程
      • 进程
      • 认证
      • 日志
      • 守护进程
      • 文件
      • 信息
      • VSFTP 配置案例
      • auditd
      • containerd
      • DNS 配置案例
      • Docker
      • Docker-Compose
      • firewalld 实验
      • gpg
      • Iptables
      • httpd
      • LAMP
      • mysql
      • nfs 配置案例
      • openssl
      • PAM
      • samba 配置案例
      • terraform
      • ufw
      • VSFTP 配置案例
    • Network
      • Speed-Net
      • Power-Net
      • SDN 笔记
      • DNS
      • TLS
    • Windows
      • Secure-Win
      • Speed-Win
      • ACL
      • LDAP
      • IPC$(Internet Process Connection)
      • PDB符号文件
      • 工作组
      • WinRM
      • 角色权限
      • 凭据
      • 签名
      • 日志
      • 认证
      • 协议
      • 信息
      • 应用
      • 组策略
      • 域
      • asp站点搭建
      • Exchange 搭建
      • Windows 故障转移集群
      • Windows 基础服务搭建
      • Windows 域搭建
      • 本地抓包
      • PowerShell 笔记
    • 容器
      • Docker
    • 数据库
      • Speed-SQL
      • Power-SQL
      • MSSQL
      • MySQL
      • Postgresql
      • Redis
      • MySQL大小写问题
      • 主键和外键
      • MySQL快速入门
      • 虚拟化
        • ESXi
        • vCenter
  • Plan
    • Mac-Plan
    • Misc-Plan
    • Team-Plan
    • Thinking-Plan
    • VM-Plan
  • Sercurity
    • Power-PenTest
    • BlueTeam
      • 安全建设
      • 分析
      • 加固
      • 取证
      • 应急
      • USB取证
      • 磁盘取证
      • 内存取证
      • ClamAV 部署
      • yara 实验
      • 安防设施搭建使用
      • ZIP明文攻击
      • 流量分析
    • Crypto
      • Crypto
        • 2020 9 G60攻防大赛
        • CTF
        • 2020 9 中能融合杯工控CTF
        • 2020 10 全国工业互联网安全技术技能大赛江苏省选拔赛
        • 2020 10 全国网络与信息安全管理职业技能大赛江苏场
        • 2020 11 I²S峰会暨工业互联网安全大赛
        • 2021 6 第二届I²S峰会暨工业互联网安全大赛
        • 2021-9-第七届工控信息安全攻防竞赛
        • 2021 9 第七届全国职工职业技能大赛某市县选拔赛
        • 2021 9 全国网络与信息安全管理职业技能大赛江苏场
        • 2021-10-G60攻防大赛
    • CTF
      • CTF
      • writeup
        • 2020 9 中能融合杯工控CTF
        • 2020 9 G60攻防大赛
        • 2020 10 全国工业互联网安全技术技能大赛江苏省选拔赛
        • 2020 10 全国网络与信息安全管理职业技能大赛江苏场
        • 2020 11 I²S峰会暨工业互联网安全大赛
        • 2021 6 第二届I²S峰会暨工业互联网安全大赛
        • 2021-9-第七届工控信息安全攻防竞赛
        • 2021 9 第七届全国职工职业技能大赛某市县选拔赛
        • 2021 9 全国网络与信息安全管理职业技能大赛江苏场
        • 2021-10-G60攻防大赛
    • ICS
      • PLC攻击
      • S7comm 相关
      • 工控协议
      • 上位机安全
      • Modbus 仿真环境搭建
      • siemens 仿真搭建实验
      • S7-300 启停实验
    • IOT
      • 无线电安全
        • RFID复制卡
        • RFID基础知识
        • WiFikiller
      • 硬件安全
        • DIY键盘嵌入指纹识别模块实验记录
        • Device-Exploits
        • HID-Digispark
        • HID-KeyboardLogger
        • HID-USBHarpoon
        • HID-USBKeyLogger
      • 固件安全
        • 固件安全
        • Dlink_DWR-932B 路由器固件分析
    • Mobile sec
      • 小程序安全
      • Android安全
    • PWN
      • SLMail溢出案例
      • PWN
    • Red Team
      • OS安全
        • Linux 安全
        • Exploits
        • NTLM中继
        • Windows 安全
        • Responder欺骗
        • Windows-LOL
      • Web_Generic
        • Top 10
          • RCE
          • Fileread
          • SQLi
          • SSRF
          • SSTI
          • Web Generic
          • XSS
          • XXE
      • Web_Tricks
        • JWT 安全
        • HTTP_request_smuggling
        • OOB
        • 绕过访问
      • 靶场
        • Hello-Java-Sec 学习
        • DVWA-WalkThrough
        • pikachu-WalkThrough
        • upload-labs-WalkThrough
        • XVWA-WalkThrough
        • XSS挑战-WalkThrough
      • 实验
        • flask
        • fastjson
        • Log4j
        • nodejs
        • Shiro
        • Spring
        • Weblogic
      • 前端攻防
      • IDOR
    • 安防设备
      • Exploits
      • Bypass 技巧
    • 后渗透
      • 权限提升
      • 后渗透
      • 权限维持
      • 实验
        • C2 实验
        • Exchange
        • 端口转发实验
        • 代理实验
        • 免杀实验
        • 隧道实验
    • 软件服务安全
      • Exploits
      • CS Exploits
      • 实验
        • Docker
        • Kubernetes
        • Mysql
        • Oracle
        • PostgreSQL
        • Redis
        • vCenter
    • 协议安全
      • Exploits
    • 信息收集
      • 端口安全
      • 空间测绘
      • 信息收集
    • 语言安全
      • 语言安全
        • 语言安全
      • GO安全
        • GO安全
        • Go代码审计
      • JAVA安全
        • JAVA安全
        • JAVA代码审计
        • JAVA反序列化
        • SpEL 注入
      • PHP安全
        • PHP安全
        • bypass_disable_function
        • bypass_open_basedir
        • phpinfo
        • PHP代码审计
        • PHP反序列化
        • PHP回调函数
        • 变量覆盖
        • POP
        • 弱类型
        • 伪协议
        • 无字母数字Webshell
      • Python安全
        • pyc反编译
        • Python安全
        • Python 代码审计
        • 沙箱逃逸
      • dotnet安全
      • JS安全
    • 云安全
      • 公有云安全
    • Reverse
      • Reverse
      • FILE
        • ELF
        • BMP
        • JPG
        • PE
        • PNG
        • ZIP
        • 文件头
      • 实验
        • PYAble
          • 2-逆运算
          • 1-基本分析
          • 3-异或
          • 4-Base64
          • 5-Base64换表
          • 6-动态调试
        • Windows
          • condrv.sys 内存损坏漏洞
    • 工具
      • Aircrack
      • BloodHound
      • Burp Suite
      • frp
      • CobaltStrike
      • Ghidra
      • fscan
      • Hashcat
      • IDA
      • merlin
      • Kali
      • Metasploit
      • Mimikatz
      • ModSecurity
      • Nmap
      • nps
      • nuclei
      • pupy
      • RedGuard
      • SET
      • sliver
      • Snort
      • Sqlmap
      • Suricata
      • Sysmon
      • uncover
      • Volatility
      • Wfuzz
      • Wireshark
      • xray
    • 安全资源
      • 靶机
        • VulnHub
          • DC
            • DC2 WalkThrough
            • DC1 WalkThrough
            • DC3 WalkThrough
            • DC4 WalkThrough
            • DC5 WalkThrough
            • DC6 WalkThrough
            • DC9 WalkThrough
            • DC8 WalkThrough
          • It's_October
            • It’s_October1 WalkThrough
          • Kioptrix
            • Kioptrix2 WalkThrough
            • Kioptrix3 WalkThrough
            • Kioptrix4 WalkThrough
            • Kioptrix5 WalkThrough
          • Mission-Pumpkin
            • PumpkinGarden-WalkThrough
            • PumpkinFestival WalkThrough
            • PumpkinRaising WalkThrough
          • Symfonos
            • symfonos1 WalkThrough
            • symfonos2 WalkThrough
            • symfonos3 WalkThrough
            • symfonos5 WalkThrough
        • Wargames
          • Bandit
            • Bandit-WalkThrough
      • 面试问题
        • 面试问题
Powered by GitBook
On this page
  • 运算符
  • 赋值运算符
  • 逻辑运算符的应用
  • 条件运算符
  • 范围运算符
  • 运算符的优先级
  • 定义运算符
  1. Develop
  2. Speed-Ruby

运算符

运算符


  • https://www.kancloud.cn/imxieke/ruby-base/107296


Ruby 的运算符能通过定义方法的方式来改变其原有的含义。

赋值运算符

正如我们之前所介绍的那样,Ruby 的变量是在首次赋值的时候创建的。之后,程序可能会对变量引用的对象做各种各样的处理,甚至再次给变量赋值。例如,对 a 变量加 1,对 b 变量乘 2,如下所示:

a = a + 1
b = b * 2

上面的表达式可被改写为以下形式:

a += 1
b *= 2

大部分的二元运算符 op 都可以做如下转换。

var op= val
↓
var = var op val

将二元运算符与赋值组合起来的运算符称为赋值运算符。

  • &&=

  • ||=

  • ^=

  • &=

  • |=

  • <>

  • >>=

  • +=

  • -=

  • \*=

  • /=

  • %=

  • \*\*=

除了变量之外,赋值运算符也同样适用于经由方法的对象操作。下面两个表达式是等效的。

$stdin.lineno += 1
$stdin.lineno = $stdin.lineno + 1

请读者注意,上面的式子调用的是 $stdin.lineno 和 $stdin.lineno= 这两个方法。也就是说,使用赋值运算符的对象必须同时实现 reader 以及 writer 存取方法。

逻辑运算符的应用

在介绍逻辑运算符的应用例子之前,我们需要先来了解一下逻辑运算符的以下一些特征。

  • 表达式的执行顺序是从左到右

  • 如果逻辑表达式的真假已经可以确定,则不会再判断剩余的表达式

  • 最后一个表达式的值为整体逻辑表达式的值

条件 1``|| 条件 2

上面的表达式一定会按照条件 1、条件 2 的顺序来判断表达式的值。条件 1 的判断结果为真时,不需要判断条件 2 的结果也可以知道整体表达式的结果为真。反过来说,只有当条件 1 的判断结果为假时,才需要判断条件 2。也就是说,Ruby 的逻辑运算符会避免做无谓的判断。下面我们来进一步扩展该逻辑表达式:

条件 1``|| 条件 2``|| 条件 3

这种情况下,只有当条件 1 和条件 2 两者都为假的时候,才会进行条件 3 的判断。这里的条件表达式指的是 Ruby 中所有的表达式。

var || "Ruby"

在上面的表达式中,首先会判断 var 的真假值,只有当 var 为 nil 或者 false 时,才会判断后面的字符串 "Ruby" 的真假值。之前我们也提到过,逻辑表达式的返回值为最后一个表达式的返回值,因此这个表达式的返回值为:

  • var 引用对象时,var 的值

  • var 为 nil 或者 false 时,字符串 "Ruby"

接下来,我们再来讨论一下 &&。基本规则与 || 是一样的。

条件 1``&& 条件 2

与 || 刚好相反,只有当条件 1 的判断结果为真时,才会判断条件 2。

下面是逻辑运算符的应用例子。假设希望给变量 name 赋值,一般我们会这么做:

name = "Ruby"    # 设定 name 的默认值
if var           # var 不是 nil 或者 false 时
  name = var     # 将 var 赋值给 name
end

使用 || 可以将这 4 行代码浓缩为一行代码。

name = var || "Ruby"

下面我们稍微修改一下程序,假设要将数组的首元素赋值给变量。

item = nil       # 设定 item 的初始值
if ary           # ary 不是 nil 或者 false 时
  item = ary[0]  # 将 ary[0] 赋值给 item
end

如果 ary 为 nil,则读取 ary[0] 时就会产生程序错误。在这个例子中,预先将 item 的值设定为了 nil,然后在确认 ary 不是 nil 后将 ary[0] 的值赋值给了 item。像这样的程序,通过使用 &&,只要像下面那样一行代码就可以搞定了:

item = ary && ary[0]

在确定对象存在后再调用方法的时候,使用 && 会使程序的编写更有效率。从数学的角度上来看,下面的逻辑表达式表达的是一样的意思,但是从编程语言的角度来看却并不是一样的。

item = ary[0] && ary    # 错误的写法

最后,我们来看看 || 的赋值运算符。

var ||= 1

和

var = var || 1

的运行结果是一样的。只有在 var 为 nil 或者 false 的时候,才把 1 赋值给它。这是给变量定义默认值的常用写法。

条件运算符

条件运算符 ?: 的用法如下:

条件 ? 表达式 1 : 表达式 2

上面的表达式与下面使用 if 语句的表达式是等价的:

if 条件
 表达式 1
else
 表达式 2
end

例如,对比 a 与 b 的值,希望将比较大的值赋值给 v 时,程序可以像下面这样写:

a = 1
b = 2
v = (a > b) ? a : b
p v    #=> 2

如果表达式过于复杂就会使程序变得难懂,因此建议不要滥用此写法。条件运算符也称为三元运算符。

范围运算符

在 Ruby 中有表示数值范围的范围(range)对象。例如,我们可以像下面那样生成表示 1 到 10 的范围对象。

Range.new(1, 10)

用范围运算符可以简化范围对象的定义。以下写法与上面例子的定义是等价的:

1..10

范围运算符有 .. 和 ... 两种。x..y 和 x...y 的区别在于,前者的范围是从 x 到 y;而后者的范围则是从x 到 y 的前一个元素。

对 Range 对象使用 to_a 方法,就会返回范围中从开始到结束的值。下面就让我们使用这个方法来确认一下 .. 和 ... 有什么不同。

p (5..10).to_a    #=> [5, 6, 7, 8, 9, 10]
p (5...10).to_a   #=> [5, 6, 7, 8, 9]

如果数值以外的对象也实现了根据当前值生成下一个值的方法,那么通过指定范围的起点与终点就可以生成 Range 对象。例如,我们可以用字符串对象生成 Range 对象。

p ("a".."f").to_a     #=> ["a", "b", "c", "d", "e", "f"]
p ("a"..."f").to_a    #=> ["a", "b", "c", "d", "e"]

在 Range 对象内部,可以使用 succ 方法根据起点值逐个生成接下来的值。具体来说就是,对 succ 方法的返回值调用 succ 方法,然后对该返回值再调用 succ 方法……直到得到的值比终点值大时才结束处理。

> irb --simple-prompt
>> val = "a"
=> "a"
>> val = val.succ
=> "b"
>> val = val.succ
=> "c"
>> val = val.succ
=> "d"

运算符的优先级

运算符是有优先级的,表达式中有多个运算符时,优先级高的会被优先执行。例如四则运算中的“先乘除后加减”。

表达式 | 含义 | 结果

  • | - | - 1 + 2 * 3 | 1 + (2 * 3) | 7 "a" + "b" * 2 + "c" | "a" + ("b" * 2) + "c" | "abbc" 3 * 2 ** 3 | 3 * (2 ** 3) | 24 2 + 3 < 5 + 4 | (2 + 3) < (5 + 4) | true 2 < 3 && 5 > 3 | (2 < 3) && (5 > 3) | true

如果不想按照优先级的顺序进行计算,可以用 () 将希望优先计算的部分括起来,当有多个 () 时,则从最内侧的 () 开始算起。因此,如果还未能熟练掌握运算符的优先顺序,建议多使用 ()。

定义运算符

Ruby 的运算符大多都是作为实例方法提供给我们使用的,因此我们可以很方便地定义或者重定义运算符,改变其原有的含义。但是,部分运算符是不允许修改的。

  • ::

  • &&

  • ||

  • ..

  • ...

  • ?:

  • not

  • =

  • and

  • or

二元运算符

定义四则运算符等二元运算符时,会将运算符名作为方法名,按照定义方法的做法重定义运算符。运算符的左侧为接收者,右侧被作为方法的参数传递。在程序中,我们将为表示二元坐标的 Point 类定义运算符 + 以及 -。

class Point
  attr_reader :x, :y

  def initialize(x=0, y=0)
    @x, @y = x, y
  end

  def inspect  # 用于显示
    "(#{x}, #{y})"
  end

  def +(other)  # x、y 分别进行加法运算
    self.class.new(x + other.x, y + other.y)
  end

  def -(other)  # x、y 分别进行减法运算
    self.class.new(x - other.x, y - other.y)
  end
end

point0 = Point.new(3, 6)
point1 = Point.new(1, 8)

p point0           #=> (3, 6)
p point1           #=> (1, 8)
p point0 + point1  #=> (4, 14)
p point0 - point1  #=> (2, -2)

如上所示,定义二元运算符时,我们常把参数名定义为 other。

在定义运算符 + 和 - 的程序中,创建新的 Point 对象时,我们使用了 self.class.new。而像下面这样,直接使用 Point.new 方法也能达到同样的效果。

def +(other)
  Point.new(x + other.x, y + other.y)
end

使用上面的写法时,返回值一定是 Point 对象。如果 Point 类的子类使用了 + 和 -,则返回的对象应该属于 Point 类的子类,但是这样的写法却只能返回 Point 类的对象。在方法内创建当前类的对象时,不直接写类名,而是使用 self.class,那么创建的类就是实际调用 new 方法时的类,这样就可以灵活地处理继承与 Mix-in 了。

puts 方法与 p 方法的不同点

上面的代码中定义了用于显示的 inspect 方法,在 p 方法中把对象转换为字符串时会用到该方法。另外,使用 to_s 方法也可以把对象转换为字符串,在 puts、print 方法中都有使用 to_s 方法。下面我们来看看两者的区别。

> irb --simple-prompt
>> str = "Ruby 基础教程"
=> "Ruby 基础教程"
>> str.to_s
=> "Ruby 基础教程"
>> str.inspect
=> "\"Ruby 基础教程\""

String#to_s 的返回结果与原字符串相同,但 String#inspect 的返回结果中却包含了 \"。这是因为 p 方法在输出字符串时,为了让我们更明确地知道输出的结果就是字符串而进行了相应的处理。这两个方法的区别在于,作为程序运行结果输出时用 to_s 方法;给程序员确认程序状态、调查对象内部信息等时用 inspect 方法。

除了 puts 方法、print 方法外,to_s 方法还被广泛应用在 Array#join 方法等内部需要做字符串处理的方法中。

inspect 方法可以说是主要使用 p 方法进行输出的方法。例如,irb 命令的各行结果的显示就用到了 inspect 方法。我们在写程序的时候,如果能根据实际情况选择适当的方法,就会达到事半功倍的效果。

一元运算符

可定义的一元运算符有 +、-、~、! 4 个。它们分别以 +@、-@、~@、!@ 为方法名进行方法的定义。下面就让我们试试在 Point 类中定义这几个运算符。这里需要注意的是,一元运算符都是没有参数的。

class Point
  ┊
  def +@
    dup                     # 返回自己的副本
  end

  def -@
    self.class.new(-x, -y)  # 颠倒x、y 各自的正负
  end

  def ~@
    self.class.new(-y, x)   # 使坐标翻转90 度
  end
end

point = Point.new(3, 6)
p +point  #=> (3, 6)
p -point  #=> (-3, -6)
p ~point  #=> (-6, 3)

下标方法

数组、散列中的 obj[i] 以及 obj[i]=x 这样的方法,称为下标方法。定义下标方法时的方法名分别为 [] 和 []=。

在代码中,定义 Point 类实例 pt 的下标方法,实现以 v[0] 的形式访问 pt.x,以 v[1] 的形式访问 pt.y。

class Point
  ┊
  def [](index)
    case index
    when 0
      x
    when 1
      y
    else
      raise ArgumentError, "out of range `#{index}'"
    end
  end

  def []=(index, val)
    case index
    when 0
      self.x = val
    when 1
      self.y = val
    else
      raise ArgumentError, "out of range `#{index}'"
    end
  end
end
point = Point.new(3, 6)
p point[0]           #=> 3
p point[1] = 2       #=> 2
p point[1]           #=> 2
p point[2]           #=> 错误(ArgumentError)

参数 index 代表的是数组的下标。由于本例中的类只有两个元素,因此当索引值指定 2 以上的数值时,程序就会认为是参数错误并抛出异常。

Previous循环NextSocket编程