Почему символы в Ruby не рассматриваются как тип переменной?
новое в программировании и Ruby, и я надеюсь, что этот вопрос о символах находится в строке. Я понимаю, что символы в Ruby (например, :book
, :price
) полезны, в частности, как хэш-ключи, и для всех вокруг делает легкий, конкретный подмножество вещей, которые строки могут сделать.
однако я смущен символами в одном отношении. В частности, когда они используются в attr_accessor
типы методов, похоже, что они ведут себя больше как переменная. Е. Г., attr_reader :book, :price
.
если верно, что они являются переменными в этом использовании, это немного озадачивает, потому что они обычно не перечислены среди типов переменных (например, $global, @instance, local, @@class, а иногда, CONSTANT, variable types) при описании типов переменных.
и если символы являются переменными при использовании таким образом, какую область следует ожидать от них? Или они все еще как-то легкие строки в этом контексте? (Или, возможно, в более широком смысле, символы, строки и переменные имеют фундаментальную утиную природу?) Заранее спасибо за ваши идеи и советы.
8 ответов
символы, используемые в методах доступа, не являются переменными. Они просто представляют имя переменной. Переменные содержат некоторую ссылку, поэтому вы не можете использовать саму переменную при определении методов доступа. Например, предположим, что вы хотите определить метод доступа для переменной @foo
в контексте, где его стоимость составляет "bar"
. Что произойдет, если синтаксис Ruby будет таким:
attr_accessor @foo
это ничем не отличается от написания:
attr_accessor "bar"
где у вас нет доступа к имя @foo
, который вас интересует. Поэтому такие конструкции должны быть разработаны для ссылки на имена переменных на метауровне. По этой причине используется символ. Они не сами переменные. Они представляют собой имя переменной.
и переменная, относящаяся к методам доступа, являются переменными экземпляра.
символы - это не переменные, а тип литерального значения, например цифры и строки с кавычками. Примечательно, что символы используются для представляют переменные и другие именованные значения в среде выполнения Ruby. Поэтому, когда интерпретатор Ruby видит имя foo
используется в качестве переменной или имени метода, то, что он ищет в хэше значений времени выполнения, является символом :foo
, а не строку "foo"
. Это было, по сути, первоначальное использование термина "символ" в терминологии языка программирования; переменные, функции, константы, методы и т. д., Как говорят, хранятся в "таблице символов"компилятора или интерпретатора.
практически каждый раз, когда вы передаете имя чего-то в Ruby, вы будете использовать символ. Если вы используете method_missing
как catch-all для реализации произвольных методов в вашем классе объектов символ-это то, что он получает в качестве аргумента, сообщающего ему имя метода, который был фактически вызван. Если вы проверяете объект с помощью .methods
или .instance_variables
, что вы get back-это массив символов. И так далее.
Они не являются переменными, потому что они не имеют ценности, они неизменны. Дело в самой ценности. Это похоже на цифры. Вы не можете установить значение 1
. 1 = 2
не работает.
attr_accessor
и таковы все методы, которые принадлежат классу, Class. Они ожидают символов в качестве аргументов. Вы можете написать свою собственную версию attr_
что б струны, если хочешь. Это просто идиома ruby. Вот пример attr_acessor
, который хранит все предыдущие значения attr_accessor
Я сделал домашнее задание.
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s # make sure it's a string
attr_reader attr_name # create the attribute's getter
attr_reader attr_name+"_history" # create bar_history getter
class_eval %Q"
def #{attr_name}=(value)
if !defined? @#{attr_name}_history
@#{attr_name}_history = [nil]
end
@#{attr_name} = value
@#{attr_name}_history << value
end
"
end
end
Руби!--0-->, attr_reader
и attr_writer
- это просто сокращенные способы избежать написания немного повторяющегося кода. Следующий вопрос расширяется о том, как они работают:почему attr_accessor использовать Руби, attr_reader и attr_writer?
вместо того, чтобы думать о attr_reader :book
как переменная, просто подумайте об этом как имя атрибута, указанного с помощью символа.
чтобы решить ваши вопросы" если верно, что они являются переменными "и" область", было бы проще ответить, что символы доступа не имеют ничего общего с переменными экземпляра, даже если это звучит iconoclastic. Они не указывают на переменные экземпляра. Аксессоры определяют только getter и setter методы. В разделе Object#instance_variables Кирка (*) говорит : Обратите внимание, что простое определение метода доступа не создает соответствующую переменную экземпляра.
In Ruby, переменная не существует, пока вы не назначите ей значение. Следующий код демонстрирует это.
class MyClass
attr_accessor :name
attr_reader :book
end
obj = MyClass.new # line 6
print '1) obj.instance_variables : '; p obj.instance_variables
print '2) obj.name : '; p obj.name
obj.name = 'xyz'
print '3) obj.instance_variables : '; p obj.instance_variables
print '4) obj.name : '; p obj.name
print '5) obj.book : '; p obj.book
class MyClass
def initialize(p_book)
@book = p_book
end
end
obj = MyClass.new('The Pickaxe') # line 21
print '6) [new] obj.book : '; p obj.book
class MyClass
method_name = 'title'
attr_accessor method_name # line 26
end
obj.title = 'Programming Ruby'
print '7) obj.instance_variables : '; p obj.instance_variables
print '8) obj.title : '; p obj.title
выход :
$ ruby -w t.rb
1) obj.instance_variables : []
2) obj.name : nil
3) obj.instance_variables : ["@name"]
4) obj.name : "xyz"
5) obj.book : nil
6) [new] obj.book : "The Pickaxe"
7) obj.instance_variables : ["@title", "@book"]
8) obj.title : "Programming Ruby"
1) пустой массив: аксессоры не определили переменные экземпляра
2) запрос, например, переменной @name отвечает nil: она не существует
3) присвоение значения создало переменную экземпляра.
Обратите внимание, что name =
является синтаксическим сахаром для использования сеттера в качестве обычного метода с параметром : obj.name=('xyz')
4) метод геттер name
отвечает на значение @name
5) метод геттер book
отвечает nil, потому что переменная экземпляра @book не существует. Определение метода доступа attr_reader :book
не определил соответствующую переменную экземпляра
6) метод геттер book
отвечает на значение, присвоенное в initialize
, называют new
в строке 21. Переменная экземпляра @book была создана @book = p_book
строка 26) я всегда считал, что аксессоры принять только атрибутика. Я обнаруживаю, что переменная возможна, но представляет ограниченный интерес.
7) метод сеттер title=
создал @title. Это также показывает, что переменные экземпляра принадлежат одному объекту. Мы часто считаем, что они принадлежат всем экземплярам класса, как и в других языках. В этом случае @name принадлежит только объекту, созданному в строке 6.
8) метод геттер title
отвечает на значение @title
class MyClass
def title # line 34
@book + ' (cheating !)'
end
end
print '9) obj.title : '; p obj.title
выход :
t.rb:34: warning: method redefined; discarding old title
9) obj.title : "The Pickaxe (cheating !)"
9) конечно, существует тесная корреляция между символом доступа и соответствующей переменной экземпляра, потому что за сценой Ruby создает методы, которые ссылаются на переменную экземпляра с тем же именем. Вы могли бы определить свой собственный добытчик и обмануть.
Обратите внимание, что помимо переменных класса (@@var, некоторые не любят их как уродливые, как глобальные переменные), классы также могут иметь переменные экземпляра. Я называю их переменными экземпляра класса:).class MyClass
: Ruby выделяет новый экземпляр класса Class определяет константу MyClass и назначает новый экземпляр этой константе. Таким образом, MyClass является обычным объектом (экземпляром класса) и как таковой может иметь переменные экземпляра.
if RUBY_VERSION[0..2] == '1.8'
class Object
def singleton_class
class << self
self
end
end
end
end
class MyClass
singleton_class.instance_eval do
attr_accessor :counter
end
@counter = 0
def initialize(p_book)
@book = p_book
self.class.counter += 1
end
end
print '10) MyClass.singleton_methods : '; p MyClass.singleton_methods
print '11) MyClass.instance_variables : '; p MyClass.instance_variables
obj = MyClass.new('Ruby')
print '12) [new] obj.book ', MyClass.counter, ': '; p obj.book
obj = MyClass.new('Metaprogramming')
print '13) [new] obj.book ', MyClass.counter, ': '; p obj.book
выход :
t.rb:55: warning: method redefined; discarding old initialize
10) MyClass.singleton_methods : ["counter", "counter="]
11) MyClass.instance_variables : ["@counter"]
12) [new] obj.book 1: "Ruby"
13) [new] obj.book 2: "Metaprogramming"
подробнее о методах singleton здесь:что делает def ' self.функция ' имя означает?
(ответ на ваш комментарий)
dog = 'dog'
или String.new("dog")
после того, как собака = строка.new, класс поля экземпляра dog указывает на строку класса.
class << dog
puts "inside #{self}" #=> inside #<Class:#<String:0x007fb38a83a820>>
def bark
puts 'woof'
end
end
dog.bark #=> "woof"
p dog.singleton_methods #=> ["bark"]
С class << dog
или def dog.bark
, Ruby создает анонимный класс, класс поля экземпляра dog теперь указывает на этот анонимный класс, а оттуда на строку. Методы, определенные в этом контексте с помощью def или define_method, входят в таблицу методов анонимного класса.
Руби 1.9.2 ввел объект#singleton_class. [Кирка] возвращает одноэлементный класс obj, создавая его при необходимости. (Я добавляю) это эквивалентно class << self; self end
.
язык программирования Ruby (O'Reiily) просто говорит : чтобы открыть eigenclass [singleton class] объекта o, используйте class
поэтому я не знаю, как читать вслух. Я читал, что некоторые предпочли бы o >> class
. Только недавно я понял, что означает это странное выражение. Я произносится: перейти от o к анонимному классу.
class << MyClass
def dog
puts 'dog as class method'
end
end
MyClass.dog #=> dog as class method
то же самое верно для класса. С class MyClass
, MyClass, как экземпляр класса, является объектом с указателем на его класс class. С def MyClass.some_method
или class << MyClass
, Ruby создает анонимный класс, который вставляется между MyClass и Class, и методы класса входят в него.
может быть, что-то вроде: "из класса, экземпляр одноэлементного объекта self
да Для "от класса / объекта" до анонимный одноэлементный класс / eigenclass / metaclass.
Но мы не создаем себя. Self (в Smaltalk, это в C++ / Java) является своего рода зарезервированным словом, которое обозначает получателя сообщения. dog.bark
: на языке ОО мы говорим, что сообщение лает в отправлено объекту собаки. Внутри метода bark
, собственная личность будет установлена к собаке, так, что мы сможем сослаться собака. Это более очевидно с
o1 = MyClass.new; o2 = MyClass.new
o1.some_method; o2.some_method
some_method должен иметь возможность ссылаться на приемник в общем виде, это o1 или o2, это это то, что я для.
круто, я думаю, вы их уже поняли. Однако почему они так важны?
символы в Ruby неизменяемы, тогда как строки изменяемы. Ты думаешь, это круто, ну и что?
предположим, у вас есть массив строк, например:
[ "a", "b", "a", "b", "a", "b", "c" ]
для каждой новой строки, которую вы создаете, ruby собирается создать строку / объект, который содержит значение "a", и поскольку строки являются изменяемыми вещами, ruby присваивает каждому из них другой идентификатор. Если бы вы использовали символы вместо этого:
[ :a, :b, :a, :b, :a, :b, :c ]
Ruby теперь будет указывать на эти символы, и он будет создавать их только один раз.
давайте сделаем некоторые бенчмаркинг:
require 'benchmark'
Benchmark.bm do |x|
x.report("Symbols") do
a = :a
1000_000.times do
b = :a
end
end
x.report("Strings") do
a = "a"
1000_000.times do
b = "a"
end
end
end
ruby -w symbols.rb
Symbols 0.220000 0.000000 0.220000 ( 0.215795)
Strings 0.460000 0.000000 0.460000 ( 0.452653)
если вы хотите увидеть все символы, которые вы уже создали, вы можете сделать:
Symbol.all_symbols
вы также можете отправить им сообщение с просьбой об их id:
:a.object_id #=> 123
:a.object_id #=> 123
"a".id #=> 23323232
"a".id #=> some_blob_number
опять же, это потому, что строки в Ruby изменчивы, а символы-нет. Символы Ruby представляют имена внутри Ruby Переводчик.
это видео действительно помогло мне: символы Руби объяснили
Я надеюсь, что это поможет вам всем.