Почему символы в 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.функция ' имя означает?

(*) http://pragprog.com/book/ruby3/programming-ruby-1-9


(ответ на ваш комментарий)

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 Переводчик.

это видео действительно помогло мне: символы Руби объяснили

Я надеюсь, что это поможет вам всем.