Почему символы в Ruby не считаются типом переменной?

Новое для программирования и Ruby, и я надеюсь, что этот вопрос о символах находится в очереди. Я понимаю, что символы в Ruby (например, :book, :price) полезны, в частности, как ключи хэша, а также для универсального создания определенного подмножества вещей, которые могут выполнять строки.

Однако я смущен символами в одном отношении. В частности, когда они используются в типах attr_accessor, похоже, что они ведут себя как переменная. Например, attr_reader :book, :price.

Если true, что они являются переменными в этом использовании, это немного озадачивает, потому что они обычно не перечисляются среди переменных типов (например, типы $global, @instance, local, @@, а иногда и CONSTANT, переменные типы) когда описываются типы переменных.

И если символы являются переменными при использовании таким образом, какую область следует ожидать от них? Или они все еще как-то легкие строки в этом контексте? (Или, может быть, в более широком смысле, символы, строки и переменные имеют общий характер утки?) Заранее благодарю вас за ваши идеи и советы.

Ответ 1

Символы, используемые в методах доступа, не являются переменными. Они просто представляют имя переменной. Переменные содержат некоторую ссылку, поэтому вы не можете использовать собственную переменную при определении методов доступа. Например, предположим, что вы хотите определить метод доступа для переменной @foo в контексте, где его значение равно "bar". Что произойдет, если синтаксис Ruby должен выглядеть следующим образом:

attr_accessor @foo

Это ничем не отличается от написания:

attr_accessor "bar"

где у вас нет доступа к имени @foo, которое вас интересует. Поэтому такие конструкции должны быть предназначены для обозначения имен переменных на мета уровне. По этой причине используется символ. Они сами не являются переменными. Они представляют собой имя переменной.

И переменная, относящаяся к методам доступа, является переменными экземпляра.

Ответ 2

Символы - это не переменные, а тип буквального значения, например цифры и цитируемые строки. Примечательно, что символы используются для представления переменных и других именованных значений в среде выполнения Ruby. Поэтому, когда интерпретатор Ruby видит имя foo, используемое как имя переменной или метода, то, что он ищет в значениях времени Hash, является символом :foo, а не строкой "foo". Это было, по сути, оригинальное использование термина "символ" в терминологии языка программирования; переменные, функции, константы, методы и т.д., как говорят, хранятся в "таблице символов" компилятора или интерпретатора.

Довольно много раз, когда вы проходите вокруг названия что-то в Ruby, вы собираетесь использовать символ. Если вы используете method_missing в качестве объекта catch-all для реализации произвольных методов в вашем объектном классе, символ является тем, что он получает в качестве аргумента, указывающим ему имя метода, который был фактически вызван. Если вы проверяете объект с помощью .methods или .instance_variables, то вы получите массив символов. И так далее.

Ответ 3

Они не являются переменными, потому что они не содержат значений, они неизменяемы. Вещь - это сама ценность. Это похоже на цифры. Вы не можете установить значение 1. 1 = 2 не работает.

Ответ 4

attr_accessor и все такие методы принадлежат классу Class. Они ожидают символов в качестве аргументов. Вы можете написать свою собственную версию attr_, которая использовала бы строки, если бы вы этого захотели. Это просто рубиновая идиома. Здесь приведен пример attr_acessor, в котором хранятся все предыдущие значения attr_accessor, которые я сделал для домашнего задания.

class Class
  def attr_accessor_with_history(attr_name)
    attr_name = attr_name.to_s   # make sure it a string
    attr_reader attr_name        # create the attribute 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

Ответ 5

Ruby attr_accessor, attr_reader и attr_writer - это просто сокращенные способы избежать написания бит повторяющегося кода. Следующий вопрос расширяет то, как они работают: Зачем использовать attr_accessor, attr_reader и attr_writer Ruby?

Вместо того, чтобы думать о attr_reader :book как переменной, просто подумайте об этом как о названии атрибута, который указан с помощью символа.

Ответ 6

Чтобы ответить на ваши вопросы "Если это то, что они являются переменными" и "сфера", было бы проще ответить, что символы доступа не имеют ничего общего с переменными экземпляра, даже если это звучит как иконоборческий. Они не указывают на переменные экземпляра. Аксессоры определяют только методы getter и setter . В Object # instance_variables, Pickaxe (*) говорит: Обратите внимание, что просто определение аксессора не создает соответствующую переменную экземпляра.

В 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) запрос экземпляра variable @name отвечает nil: его не существует
3) присвоение значения создало переменную экземпляра.
Обратите внимание, что name = является синтаксическим сахаром для использования сеттера в качестве обычного метода с параметром: obj.name=('xyz')
4) метод getter name отвечает на значение @name
5) метод getter book отвечает nil, потому что переменная экземпляра @book не существует. Определение аксессора attr_reader :book не определило соответствующую переменную экземпляра
6) метод getter book отвечает на значение, назначенное в initialize, вызывается new в строке 21. Экземпляр переменной @book был создан @book = p_book
строка 26) Я всегда считал, что аксессоры принимают только символы. Я обнаружил, что переменная возможна, но имеет ограниченный интерес.
7) метод setter title= создал @title. Это также показывает, что переменные экземпляра принадлежат одному объекту. Мы часто считаем, что они принадлежат ко всем экземплярам класса, как и на других языках. В этом случае имя @принадлежит только объекту, созданному в строке 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 здесь: Что означает определение` self.function`?

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

Ответ 7

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

dog = 'dog' или String.new("dog")

После dog = String.new класс поля экземпляра dog указывает на класс String.

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 теперь указывает на этот анонимный класс, а оттуда - на String. Методы, определенные в этом контексте с def или define_method, входят в таблицу методов анонимного класса.

В Ruby 1.9.2 введен объект # singleton_class. [The Pickaxe] Возвращает одноэлементный класс obj, создавая при необходимости. (Я добавляю) Это эквивалентно class << self; self end.

Язык программирования Ruby (O'Reiily) просто говорит: чтобы открыть eigenclass [singleton class] объекта o, используйте класс < < о.

Поэтому я не знаю, как читать это громко. Я прочитал, что некоторые предпочитают 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 и классом, и методы класса входят в него.

Может быть что-то вроде: "из класса, экземпляр объекта singleton self

Да для "от класса/объекта" до анонимного одноэлементного класса/eigenclass/метакласса. Но мы не создаем себя. Self (в Smaltalk, это на С++/Java) является своего рода зарезервированным словом, которое обозначает получателя сообщения. dog.bark: на языке OO мы говорим, что сообщение коры отправлено объектной собаке. Внутри метода bark self будет установлен на собаку, чтобы мы могли ссылаться на собаку. Это более очевидно с помощью

o1 = MyClass.new; o2 = MyClass.new
o1.some_method; o2.some_method

some_method должен иметь возможность ссылаться на приемник в общем виде, является ли это o1 или o2, это то, что для себя является.

Ответ 8

Прохладный, я думаю, вы понимаете их уже сейчас. Однако почему они так важны?

Символы в 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

Вы также можете отправить сообщение им с запросом об их идентификаторе:

:a.object_id #=> 123
:a.object_id #=> 123

"a".id #=> 23323232
"a".id #=> some_blob_number

Опять же, потому что строки в Ruby являются изменяемыми, а символы - нет. Символы Ruby представляют имена внутри интерпретатора Ruby.

Это видео действительно помогло мне: Объяснение Ruby Symbols

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