符号是具名标识符,可以用来指代某个值。符号通过符号字面量创建,做法是在名称前加上 : 字符,例如 :foo。符号也可以写成带引号的形式,例如 :"foo",这样一来,名称中就可以包含空格等内容。
:foo # => :foo
:"foo boo" # => :"foo boo"
符号在这门语言中用途广泛,包括用作哈希的键,以及表示方法名和变量名。
符号与字符串的区别在于,符号是标识符,并不表示数据或文本。这意味着同名的两个符号永远是同一个对象。
"foo".object_id # => 60
"foo".object_id # => 80
:foo.object_id # => 1086748
:foo.object_id # => 1086748
符号是不可变的,这意味着它们不能被修改。因此,当你“修改”一个符号时,实际上是在创建一个新符号。有几个方法可以用来操作符号,它们都会返回新的符号。所有方法都可以在 Symbol API 中找到。
:foo.upcase # => :FOO
:foo.object_id # => 1086748
:foo.upcase.object_id # => 60
符号不可变的好处是,它们比字符串更节省内存,用作标识符也更安全。
符号可以转换成字符串,反过来也可以。当你想修改一个符号,或者想把符号当作字符串使用时,这会很有用。要把字符串表示为符号,可以使用 String#to_sym 方法;要反过来,可以使用 Symbol#to_s 方法。由于符号可用的方法数量有限,如果需要得到一个新符号,先把符号转成字符串,再对它使用字符串方法,会很有用。
:foo.to_s # => "foo"
"foo".to_sym # => :foo
帕勒莫港是一个繁忙的港口,船只来来往往。长期以来,它一直靠一套人工系统来记录当前停靠在港内的船只。这套系统非常容易出错,于是港务长决定用一套计算机化的系统来取代它。
港务长雇请你来实现这套新系统。这套系统既要处理船只的标识符,也要处理目的地的标识符。
你首先要做的,是为帕勒莫港创建标识符。标识符是港口名称的前四个字母,并且要大写。
定义Port::IDENTIFIER常量,让它成为一个值为:PALE的符号。
Port::IDENTIFIER
# => :PALE
程序还需要处理其他港口,所以你也得为它们创建标识符。港口希望这套系统能自动运行,而由于各个港口的命名习惯不同,标识符应当根据港口的名称生成。标识符是港口名称的前四个字母,并且要大写。
定义Port.get_identifier方法,让它接收一个字符串作为实参,并以符号的形式返回该港口的标识符。
Port.get_identifier("Hamburg")
# => :HAMB
港口有两个码头,系统需要判断船只应该停靠在哪个码头。停靠哪个码头由船只的标识符决定。
标识符由 2 个部分组成:第一部分是 3 个大写字母,表示船上装载的是哪种货物;然后是 3 个数字,也就是这艘船的唯一标识符。
如果船只标识符中表示货物的部分是OIL或GAS,船只应停靠在A码头。否则船只应停靠在B码头。
定义Port.get_terminal方法,让它接收一个符号作为实参,也就是船只的标识符。该方法应以符号的形式返回码头。
Port.get_terminal(:OIL123)
# => :A