理解 Ruby Symbol,第 1 部

http://www.ibm.com/developerworks/cn/opensource/os-cn-rubysbl/

Symbol 是什么

Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。

创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号:

创建 symbol 对象


:foo
:test


:”abc”

:”I am a boy”


你可能会问,字符串就是字符串,干吗还有字符串的名字?这是因为在 Ruby 中字符串也是一种对象,即 String 对象。无论其结构还是操作和 Symbol 对象都是不同的。

在 Ruby 中每一个对象都有唯一的对象标识符(Object Identifier),可以通过 object_id 方法来得到一个对象的标识符。我们来看看 Symbol 对象和 String 对象的差别:

Ruby 对象标识符


irb(main):001:0> puts :foo.object_id
327458
=> nil
irb(main):002:0> puts :foo.object_id
327458
=> nil
irb(main):003:0> puts :"foo".object_id
327458
=> nil
irb(main):004:0> puts "foo".object_id
24303850
=> nil
irb(main):005:0> puts "foo".object_id
24300010
=> nil
irb(main):006:0> puts "foo".object_id
24296170
=> nil


可以看到,前三行语句中的 :foo (或者 :"foo")都是同一个 Symbol 对象,其 object id 为327458,而后三行中的字符串”foo”都是不同的对象,其 object id 依次为24303850、24300010、24296170。

可见,每个 String 对象都是不同的,即便他们包含了相同的字符串内容;而对于 Symbol 对象,一个名字(字符串内容)唯一确定一个 Symbol 对象。

值得注意的是创建 Symbol 对象的字符串中不能含有’\0’字符,而 String 对象是可以的。

非法 Symbol 字符串


irb(main):001:0> :"fo\0o"
SyntaxError: compile error
(irb):1: symbol cannot contain '\0'
from (irb):1
irb(main):002:0> :"foo\0"
SyntaxError: compile error
(irb):2: symbol cannot contain '\0'
from (irb):2
irb(main):003:0> puts "foo\0".object_id
24305140
=> nil
irb(main):004:0> puts "fo\0o".object_id
24301000
=> nil
irb(main):005:0>


除了可以采用一般的字符串,还可以使用操作符(例如+, -, *, /),变量,常量,方法甚至类的名字来创建 Symbol 对象,例如:+就是一个合法的 Symbol 。实际上,在 Ruby 内部操作符、变量等名字本身就是作为 Symbol 处理的,例如当你定义一个实例变量时, Ruby 会自动创建一个 Symbol 对象,例如 @test 对应为 :@test 。

实例变量的 Symbol


class Test
attr_accessor :test
end


这个类定义了一个具有读写方法的实例变量 @test 。实际上 Ruby 创建了两个 Symbol ,一个是实例变量的 symbol :@test ,另一个是 :test 。那如果使用字符串对象 ”test” 作为参数呢?也可以,仍然会创建两个 symbol ,:test 和 :@test ,为什么还会创建 :test 呢?这是和Ruby的实现相关的(至少Ruby1.8.6里是这样)。

注意,类变量 @@test 和实例变量 @test 对应的 Symbol 显然是不同的。记住:名字相同,则 Symbol 相同。

名字相同, Symbol 相同


class Test
puts :Test.object_id
Test = 10
puts :Test.object_id

def Test
puts :Test.object_id
end
end

Test.new.Test


运行结果


224298
224298
224298


名字不同, Symbol 不同


class Test
puts :Test.object_id

@@test = 10
puts :@@test.object_id
def test
puts :test.object_id
@test = 10
puts :@test.object_id

end
end

t =Test.new
t.test


运行结果


224298
288068
79858
288108


第一个例子里,类名、常量名和方法名都是 Test ,因此相应的 Symbol 对象都是 :Test 。不用担心, Ruby 可以很好区分它在不同上下文中到底表示什么。当然这并不是一个好的编程风格,但对于理解 Ruby 的 Symbol 还是有帮助的: Symbol 表示一个名字,仅此而已。

Symbol 对象一旦定义将一直存在,直到程序执行退出。所有 Symbol 对象存放在 Ruby 内部的符号表中,可以通过类方法 Symbol.all_symbols 得到当前 Ruby 程序中定义的所有 Symbol 对象,该方法返回一个 Symbol 对象数组。由于 Symbol 比较多,你可以 dump 到文件中来查看。

all_symbols 方法


irb(main):001:0> Symbol.all_symbols.size
=> 4047
irb(main):002:0> Symbol.all_symbols[0..9]
=> [:@level_notifier, :ppx, :msg_dn, :version, :secs, :@user, :pos, :socketpair,
:TkENSURE, :HTTPAccepted]
irb(main):003:0> File.open("sym", "w") do |file| file.puts Symbol.all_symbols end
=> nil


回页首


Symbol 和 String

Symbol 对象和 String 对象是完全不同的东西,对象标识符很明确的说明了这一点。除此之外,我们还可以从两种对象的方法上区分。

查看 Ruby 库参考,你会发现 String 类有非常多的方法,包括 Mixed-in 方法(Ruby中一个类通过 include 其他模块而得到的方法,实现多重继承的效果)、类方法和实例方法;而 Symbol 类只有一个类方法 all_symbols 和7个实例方法。

例如,可以通过 []= 方法改变 string 的内容,而 symbol 则不行:

[]= 方法比较


irb(main):001:0> s="test"
=> "test"
irb(main):002:0> s[0]='1'
=> "1"
irb(main):003:0> puts s
1est
=> nil
irb(main):004:0> sym=:test
=> :test
irb(main):005:0> sym[0]=1
NoMethodError: undefined method `[]=' for :test:Symbol
from (irb):5
irb(main):006:0>


虽然 Symbol 和 String 是不同的对象,但它们之间关系很密切。 Ruby 提供了方法在 Symbol和 String 之间转换。

Symbol 转化为 String

使用 to_s 或 id2name 方法将 Symbol 转化为一个 String 对象:

Symbol 到 String


irb(main):001:0> :test.id2name
=> "test"
irb(main):002:0> :test.to_s
=> "test"
irb(main):003:0> :"I am a boy".to_s
=> "I am a boy"


注意,每个 String 对象都是唯一的,因此对一个 Symbol 调用多次将产生多个 String 对象。

String 转化为 Symbol

除了在字符串前面加冒号,还可以使用 to_sym 或 intern 方法将 String 转化为 Symbol ,如果该 Symbol 已经存在,则直接返回。

String 到 Symbol


irb(main):001:0> var1 = "test".to_sym
=> :test
irb(main):002:0> var2 = "test".intern
=> :test
irb(main):003:0> var1 == var2
=> true
irb(main):004:0>


回页首


使用 Symbol

正如前边提到的, Ruby 内部一直在使用 Symbol ,比如 Ruby 程序中的各种名字,Symbol本质上是 Ruby 符号表中的东西。使用 Symbol 处理名字可以降低 Ruby 内存消耗,提高执行速度,这点我们在下一篇文章中会看到。

那么 Symbol 对我们有什么用呢?当然也是内存。使用 String 的开销太大了,因为每一个String 都是一个对象。想想前边的例子,一个字符串每出现一次 Ruby 就会创建一个 String 对象。

通常来讲,当你面临 String 还是 Symbol 的选择时,可以参考以下标准:

* 如果使用字符串的内容,这个内容可能会变化,使用 String

* 如果使用固定的名字或者说是标识符,使用 Symbol

那么什么时候我们会用到名字呢?很多时候都会,比如枚举值、关键字(哈希表关键字、方法的参数)等等

作为哈希表的 key

哈希表是 Symbol 应用最为广泛的地方。

在ruby中,哈希和数组类似,一个哈希表是一系列 key/value 对的集合,只不过它的 key 取值范围更广泛,可以是任何对象,比如正则表达式。但通常我们都会取有意义的 key ,比如 String、Symbol 。

下面这个哈希表表示按城市分类的一些机器的集合。

一个哈希表例子


hosts{
'beijing' => 'machine1',
'shanghai' => 'machine2',
'guangzhou' => 'machine3',
'tianjin' => 'machine4',
'shenzhen' => 'machine5'
}


如果要引用 beijing 的机器,使用 hosts['beijing'] 。但如果我们程序中要频繁引用哈希表中 value ,这样就不大好了,因为 Ruby 对每一次字符串引用都会生成一个 String 对象,累积下来这个开销是相当大的。

我们完全可以使用 Symbol ,因为对于这些 key 来讲,我们用的就是名字而已,例如下面hosts[:beijing]


使用 Symbol 作为 key


hosts = {
 :beijing => 'machine1',
 :shanghai => 'machine2',
 :guangzhou => 'machine3',
 :tianjin  => 'machine4',
 :shenzhen => 'machine5'
}


哈希参数

通常我们定义的函数的参数的个数和顺序是写死的,调用函数的时候要确保参数的个数、顺序匹配,有时候这样很不方便,使用哈希参数可以解决这个问题。

ROR 中就大量地运用这种方式,也许你已经看到了,到处都是 Symbol 和哈希。比如:

使用哈希参数的方法调用


link_to 'Show', :action => 'show', :id => product

add_column :products, :price, :decimal,
:precision => 8, :scale => 2, :default => 0


使用哈希参数的方法可以如下定义,前半部分为固定参数,后面为可变参数,或者干脆全采用哈希参数:

哈希参数


def my_method(para1, …, options={})
#your code
end

def my_method(options={})
#your code
end


如果你希望设定一些默认参数,并允许调用者更改这些参数,可以使用哈希对象的 merge! 方法

hsh.merge!( other_hash )。该方法将 other_hash 里内容加到 hsh 中,如果other_hash 与 hsh 有重复的 key ,则 key 在 other_hash 中的 value 覆盖 hsh 中对应 key 的 value 。

方法定义-使用默认参数


class Test
def my_method(opts={})
default_opts={:arg1 => 10, :arg2 => "abc"}
default_opts.merge!(opts)
default_opts.each{|key,value| puts "#{key} is #{value}"}
end
end

t = Test.new
t.my_method :arg1=>5, :arg3=>"def"


运行结果


arg1 is 5
arg2 is abc
arg3 is def


在 Rails 中,对 hash 类进行了扩展,可以使用 reverse_merge! 方法来达到上述效果。该方法在 ActiveSupport::CoreExtensions::Hash::ReverseMerge 中定义。Rails 甚至还提供了 assert_valid_keys 方法,对传递进来的哈希表的 keys 进行合法性检验。

Perl 说,条条大路通罗马。在 Ruby 中也是这样的,也许你会发现更好的应用 Symbol 和哈希的方法。

下篇文章我们将深入 Ruby 内部来看看 Symbol 的样子。


回页首


参考资源 (resources)

* 在 Ruby 的官方网站可以得到各种 Ruby 信息:下载、文档、社区
* Ruby on Rails(ROR) 的官方网站,你可以浏览 Rails 的方方面面:API、CoreLib等
* 在 RubyForge 找到更多 Ruby 开源项目。
* 一个不错的Ruby 学习站点,有一些关于 Symbol 的内容。
* 阅读 developerWorks 上的文章“使用Ruby on Rails 快速开发Web 应用程序”
* “Programming in the Ruby language” (developerWorks) Ruby 编程简介。
* Programming Ruby: The Pragmatic Programmer's Guide 的在线版本。


关于作者



田强,任职于 IBM 中国软件开发中心 Tivoli 部门,喜欢开源和 Linux
从零开始:在Unity中使用Dynamic Bone实现角色骨骼自然抖动(以女性角色胸部为例) 本文详细介绍了在Unity中使用Dynamic Bone插件实现角色骨骼自然抖动的完整流程,特别以女性角色胸部为例。从插件导入、骨骼系统基础到Dynamic Bone组件配置和参数调优,提供了全面的技术指导。文章还包含性能优化技巧和常见问题解决方案,帮助开发者快速掌握这一物理效果实现方法。 阅读详情

相关推荐

基于深度学习方法(7种)的高光谱与多光谱图像融合(附代码+3个数据集获取)

其他不懂的可以把代码发给AI哦,让它给你解读。

热爱分享,热爱记录 1298

Symbol 类型

Symbol 类型 1. Symbol 声明 根据规范,对象的属性键只能是字符串类型或者 Symbol 类型 Symbol 是一种基本数据类型,Symbol()函数会返回 symbol 类型的值,Symbol 值是唯一的标识符,不会与其他属性名产生冲突 Tips:Symbol 函数前不能使用 new 命令,会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象类型 let symbol1 = Symbol(); let symbol2 = Symbol(); console.log(symb

langmanboy的博客 1674

初识Renode

1. 简介 Renode是Antmicro公司发布的一个开发框架,使得开发人员通过模拟物理硬件系统(包括CPU、外围设备、传感器、环境以及节点之间的有线或无线介质),加速物联网和嵌入式系统的开发。它可在PC上通过软件对嵌入式设备进行模拟,可模拟Cortex-M、Cortex-A、RISC-V和其他CPU,并可模拟外设以及各种通信总线和接口。其指令模拟器使用C语言开发,外设模拟器使用C#语言开发,测试及输出层面的内容则用python编写。 Renode官网:Renodehttps://renode.io/

牧羊女 5291

什么是符号(Symbols)?

什么是符号(Symbols)?在编程中,一个符号(symbol)是一个程序的创建块:它是一个变量名或一个函数名。 正如你自己编制的程序一样,内核具有各种符号也是不应该感到惊奇的。当然,区别在 于内核是一非常复杂的代码块,并且含有许多、许多的全局符号。

小伟 5150

python编程实现制作网络流量监控动画

c,实时显示网络带宽使用情况,用柱状图或折线图表示不同时间段的流量变化。通过 Python编程实现图形库(如 Pygame、Tkinter、Matplotlib 等)来实现计算机网络基础概念的可视化动画。global bars # 声明 bars 为全局变量。# 获取当前网络流量。# 创建图形和坐标轴。

qq_42788199的博客 718

TC3XX - MCAL知识点(三十三):基于EB Tresos配置Tc3xx的MCAL代码如何产生中心对称的三相六路发波波形

本文用于记录如何在英飞凌 tc3xx 芯片的应用开发中,借助 EB Tresos 配置工具生成的配置代码与 MCAL 源码相结合,进而实现三相六路中心对称互补的 PWM 输出效果。外部资源需求:EB Tresos23.0以上、Tasking\Hightec编译器、示波器\逻辑分析仪。

梦想技术家 1210

【Java】 Java中“Cannot find symbol”或“Cannot resolve symbol”错误解析

/ z未定义运行结果:编译时会提示“Cannot find symbol”错误,因为变量z没有在代码中声明。

baidu_23445983的博客 4246

Python爬虫-爬取猫眼演出数据

本文是该专栏的第53篇,后面会持续分享python爬虫干货知识。猫眼平台除了有影院信息之外,它还涵盖了演出信息,比如说“演唱会,音乐节,话剧音乐剧,脱口秀,音乐会,戏曲艺术,相声”等等各种演出相关信息。而本文,笔者将以猫眼平台为例,基于Python爬虫实现获取各种演出信息的数据。废话不多说,具体细节部分以及详细思路逻辑,笔者将在正文结合完整代码进行详细说明。(附带完整代码)

Python进阶专栏《爬虫实战进阶》,《Pyppeteer从入门到精通》原创作者 568

解决 IDEA 报错: “java 找不到符号“(“cannot find symbol“)

找不到符号”(缺少导入语句。拼写错误。类路径问题。未编译的文件。IDE 配置问题。通过仔细检查代码、导入语句、类路径以及 IDE 设置,通常能够顺利解决这一错误。希望本文的总结能够帮助你排查和解决 IDE 中的 “找不到符号” 错误。

小蜗牛的珍贵百宝箱 1万+

《一》:LBE,VR 大空间系列——场景环境需求解析

当前,大量 VR 体验活动在室内场地开展。因此,对于场地照明有特定要求:除天花板外,场地的所有表面均需有照明覆盖。这是为了保证玩家无论处于场地的哪个位置,地面与墙面都不会出现明显的影子。场地内不建议安装射灯或高强度的点光源,若已安装此类灯具,需使用柔光板进行遮盖。此外,要避免在阳光下使用 VR 设备台。参考图(请忽略其中Maker标签)

unitygroup的博客 943

RT-Thread littefs控制GD32F4xx片内Flash

GD32F4xx RT-Thread下使用littefs 控制片内flash 调试记录

madao1234的博客 995

理解 Ruby Symbol ,第 2 部分: Symbol 内幕

理解 Ruby Symbol ,第 2 部分: Symbol 内幕 本文介绍 Ruby Symbol 的内部实现。结合上篇“理解 Ruby Symbol,第 1 部分:使用 Symbol”,您可以更好地理解并使用 Symbol ,感受 Ruby 的魅力。在上一篇《理解 Ruby Symbol ,第 1 部分:使用 Symbol 》中,我们大致了解了 Symbol,包括 Symbol

322

Newton & Nvidia 开源 GPU 加速机器人仿真器入门教程(一)

Newton 是一个 GPU 加速、可扩展和可微分的物理仿真引擎,专为机器人、研究和高级仿真工作流而设计。Newton 基于 NVIDIA Warp 并集成了 MuJoCo Warp,为用户和开发人员提供了高性能仿真、现代 Python API 和灵活的架构。

机器人控制与仿真应用 1482

理解 Ruby Symbol (Ruby中的冒号)

Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。 创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号: 创建 symbol 对象 :foo :test

琉璃BES 3万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Ruby之symbol研究

       这是一个研究笔记,主要是为了向同好请教。除了这个开头以外,没有多余的废话,也就免了其他的客套。请大家不要抱怨可读性不好。1. 在一个名字或者字符串前面加上冒号,得到一个symbol对象。还可以通过String#to_sym、Fixnum#to_sym和String#intern得到。2. 一般用symbol做hash的key,号称是为了节省内存,提高执行效率。3. 为什么

孟岩 1万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

理解 Ruby Symbol,第 1 部分

Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。 创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号: 创建 symbol 对象 :foo :test :”abc”

dazhi_100的专栏 575

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

理解 Ruby Symbol (Ruby中的符号)

转自:[http://blog.youkuaiyun.com/besfanfei/article/details/7966850]Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。 创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号: 创建 symbol 对象 :

Richar1的专栏 3852

Ruby 中的 symbol 符号

name中的是 Ruby 中定义符号(Symbol)的方式。符号用于表示名字、标识符、键等,效率高且唯一。在中,:name表示你要为实例变量@name自动生成 getter 方法。推荐在需要表示“名字”的地方使用符号,而不是字符串。如果你理解了符号的概念,你会发现它在 Ruby 中无处不在,比如 Hash 的键、方法名、状态标识等都非常适合用符号来表达。

Java的专栏 772

if 条件前 && 赋值语句注意点,Ruby里面神奇的Symbol,为何要用Symbol?

[41] pry(main)> def abc [41] pry(main)* self[0] = 1 && self[1] = 2 if self[0,1] [41] pry(main)* end => :abc [42] pry(main)> aaa = [100,200,300] => [100, 200, 300] [43] pry(main)&...

qq_42672332的博客 404

理解 Ruby Symbol

在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。 创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号: 有读者可能会问,为什么要存在 Symbol 对象呢?因为 symbol 可以大大提高速度。Symbol 的内

ESR研发中心 CTO兼创始人 王加杉 599

理解 Ruby Symbol,

Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。 创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号: 创建 symbol 对象 :foo :test :

琉璃BES 521
上一篇: 跨越边界: 闭包
下一篇: Install MySQL Server 5 on Ubuntu
wavee
博客等级 码龄22年 0粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值