Skip to content

Latest commit

 

History

History
603 lines (397 loc) · 30.1 KB

ruby.md

File metadata and controls

603 lines (397 loc) · 30.1 KB

Вопросы по Ruby с собеседований

  1. Какие типы данных используются в Ruby? Что такое массив? хэш? строка? число? время? символ?

    Ответ

    Числа

    Числа (Numeric) в Ruby выглядят так:

    5 # целое число Integer
    -12 # отрицательное целое число
    076 # восьмеричное число
    0b010 # двоичное число
    0x89 # шестнадцатиричное число
    4.5 # число с плавающей точкой Float
    2+3i # комплексное число Complex
    Rational(2, 3) # рациональная дробь ⅔ Rational

    Логический тип

    Логический (булевый) тип — это вариация на тему «да» или «нет». В Ruby он представлен двумя предопределёнными переменными true («истина» или «да») и false («ложь» или «нет»). Появляется логический тип в результате логических операций или вызова логических методов (обычно заканчиваются на знак вопроса ?).

    Чаще всего логический тип возникает как результат сравнения.

    true возвращает любой объект, в т.ч. 0, за исключением false и nil (nil — это символ пустоты).

    Массивы

    Разработчики Ruby решили не реализовывать особых классов для динамических массивов, списков, стеков и тому подобного. Они все это реализовали в массивах — структурах данных типа (или класса — в Ruby всё равно) Array. Сделано это путём добавления специальных методов; например, методы .push и .pop для стека.

    Особенности массивов в Ruby:

    • Нет ограничений (это общий принцип языка). Массивы могут быть сколь угодно длинными.
    • Динамичность: размер массива легко меняется.
    • Гетерогенность: один массив может хранить данные разных типов.
    • Библиотека итераторов на каждый случай жизни. Эта возможность позволяет не использовать циклы для обработки данных в массивах, а, следовательно, избегать множества ошибок, связанных с неосторожным обращением с циклами. Итераторы реализуются на высочайшем уровне.
    • Много других методов. Все элементарные задачи для массивов решаются вызовом нужного метода.
    [1, 0, 740, 14, 25] # целочисленный массив
    
    ["a", "й", "6", 'Br', "Это массив строк"]
    
    [[1, 2], [3, 4]] # двумерный целочисленный массив; Матрица — это объект класса Matrix
    
    # Двумерный массив — это не матрица целых чисел
    ["1-й элемент смешанного массива", "7.343", [4, "вепрь"], [3, 67, 4326, 12, 3781357, 84221, "строка делает этот подмассив смешанным, но это не беда"]]
    
    array = ["Этот массив пойдёт в переменную array", "Як-цуп-цоп, парви каридулла"]

    Строки

    Стро́ки (String) — это ряды букв и других символов. В Ruby стро́ки используют наработки языка Perl.

    Стро́ки начинаются и заканчиваются " (программистскими кавычками) или ' (машинописным апострофом).

    Чаще принято использовать одинарные кавычки. Однако в случае интерполяции и применении спецсимволов таких, как \t, \n, 'используются двойные.

    Вот небольшой список их возможностей:

    • Нет ограничений. Длина строки́ может достигать поистине фантастических размеров.
    • Динамичность. Стро́ки можно расширять или уменьшать (для этого есть методы + и []).
    • Любой объект преобразуется в строку (методы .inspect и .to_s есть у любого объекта).
    • Строка обладает обширной библиотекой методов, которые работают с правилами (это методы .gsub, .match, .scan, .split).
    • Конкатенация и интерполяция
    '2' + '2' #=> "22" # конкатенация
    
    name = 'Вася'
    "Привет, #{name}!" #=> "Привет, Вася" # интерполяция

    Ассоциативные массивы

    Ассоциативные массивы (класс Hash) подобны массивам упорядоченных пар.

    Работают они подобно словарям: фигурная скобка символизирует боковой вид на открытую книгу, а стрелка => покажет читателю связь каждой сущности с какой-то другой. Вторая фигурная скобка говорит, что пора закрывать книгу.

    Структурными элементами хеша являются ключи и соответствующие им значения.

    hash = { "мама" => "мыла раму", 807 => "Это число улыбается!" }
    
    hash["мама"] #=> "мыла раму"
    hash["807"] #=> nil
    hash[807] #=> "Это число улыбается!"

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

    Wife.new(age: 18, bust: 90, waist: 60, hips: 90)

    Ассоциативные массивы оставляют возможность хранения данных разного типа только в ассоциативном виде.

    Диапазоны значений

    Чтобы было удобней получать подмассив или подстроку, был введён тип данных — диапазон (класс Range).

    Диапазон формируется тремя элементами: начало, конец и тип протяжённости (символ .. или ...).

    Начало и конец должны быть одного типа данных (одного класса) и быть перечислимыми, что значит, иметь метод .succ (succedent — «последующему»).

    Применение .. подразумевает включение конечного элемента. Применение ... исключает конечный элемент.

    Пример диапазонов:

    "a".."z"
    "a"..."z" # то же, что и "a".."y"
    1..100
    1...100 # то же, что и 1..99

    Начиная с версии 2.6.0 вводится понятие бесконечного диапазона.

    Пример применения:

    array[3..] # возвратит массив с элементами array, соответствующие индексом от 3-го до последнего 

    Символы

    В Ruby есть особый класс Symbol. Синтаксически объекты этого класса обозначаются двоеточием.

    Например, :a, :b, :symbol.

    Символ похож на строку (String). Одно из главных отличий заключается в том, что у каждого символа есть только один экземпляр.

    Что это означает на практике? И в чём отличие от строки?

    Например, у нас есть такие объекты:

    a = "slovo"
    b = "slovo"
    c = "slovo"
    
    d = :slovo
    e = :slovo
    f = :slovo

    Дело в том, что в этом примере объекты a, b и c — это три разных объекта, они ссылаются на разные ячейки в памяти компьютера.

    А вот объекты d, e и f — это всё один объект. В этом легко убедиться:

    a.object_id #=> 47103948599080
    b.object_id #=> 47103948574540
    c.object_id #=> 47103948569400
    
    d.object_id #=> 1294428
    e.object_id #=> 1294428
    f.object_id #=> 1294428

    Символы часто используются в хэшах в качестве ключей. Одна из причин этого вытекает из свойств символов иметь лишь один экземпляр. Это позволяет экономить потребление памяти компьютера.

    Ещё одно свойство символов — статичность. Т.е. к ним нельзя применить методы, подобные downcase или +.

    И ещё одно важное применение символов, когда к ним применяется метод to_proc.

    downator = :downcase.to_proc
    downator.call('STROKA') #=> "stroka"

    Как это работает? Дело в том, что в переменной downator хранится блок proc { |arg| arg.downcase }

    На практике такое свойство часто применяют при операциях с массивами, например:

    ['STROKA', 'SLOVO'].map(&:downcase) #=> ["stroka", "slovo"]
  2. Какие структуры есть в ruby?

    Ответ Что такое struct, abstract, open struct Структуры в Руби следующие:
    • struct
    • abstract
    • openstruct

    Структуры позволяют так же работать с методами по примеру полного аналога класса. Полностью заменяют классы и возможно даже немного удобнее их. Но все пишут что не надо заменять структуры на классы полностью, они могут быть хороши только в не больших размерах и объемах коллекций.

    struct и open struct это упрощенная форма создания классов, в котором мы указываем что должно быть передано в struct для вывода программы.

    • struct — принимает четкое кол-во параметров для вывода программы.
    person = :name, :age
    
    p.name = "Karthik"
    p.age = 30
    
    puts "Hello, I am #{p.name}, age #{p.age}"

    либо

    person =  :name, :age
    
    p =  "Karthik", 30
    
    puts "Hello, I am #{p.name}, age #{p.age}"

    OpenStruct — не ругается, если параметров передано больше чем есть.

    require 'ostruct'
    
    p.name= "Karthik"
    p.age = 30
    
    puts "Hello, I am #{p.name}, age #{p.age}"
  3. Что такое loop, while, map, each?

    Ответ

    loop, while — это управляющие конструкции, создающие циклы, повторение кода по условию/без условий.

    each, map — итераторы, перебирают все элементы у объекта (унаследованы от Numerable).

    Итераторы — это методы, которые принимают блоки и выполняют код в блоках для элементов коллекций (массивов, интервалов или хэшей).

    https://www.rubyguides.com/ruby-tutorial/loops/

    https://www.rubyguides.com/2018/10/ruby-map-method/

    http://rubycode.ru/ruby/osnovy/57-chislovye-iteratory.html

    http://queirozf.com/entries/ruby-map-each-collect-inject-reject-select-quick-reference

  4. Чем отличается each от map ?

    Ответ

    each занимается просто перебором, map занимается перебором и конечным выводом измененного массива, также можно map вызвать с помощью bang-метода для изменения исходного массива.

  5. Какие ещё циклы и итераторы есть в Ruby?

    Ответ

    Циклы until, for

    Итераторы times, upto, downto, step

    https://i-love-ruby.gitlab.io/#_loops

  6. Какие переменные бывают, где они используются, где они доступны (поля видимости)?

    Ответ

    Локальные переменные variable — локальная переменная, она доступна только в той области видимости, где была определена.

    Переменные экземпляра класса @variable — доступны только в методах экземпляра класса, где они определены. При первом вызове возвращают nil.

    Глобальные переменные $variable — область видимости — вся программа (опасно использовать, т.к. потом сложно изменить, где и кто её поменял).

    Переменные класса @@variable — область видимости — класс в котором они определены и все экземпляры данного класса.

    http://rubycode.ru/ruby/osnovy/54-oblast-vidimosti-i-tipy-obektov.html

  7. Что такое переменная с одной @ и переменная с двумя @@?

    Ответ

    Переменные экземпляра класса @variable — начинаются с @. Переменные экземпляра класса доступны в методах экземпляра класса, где они определены.

    Переменные класса @@variable — начинаются с двух символов @. Их область видимости — класс в котором они определены и все экземпляры данного класса.

  8. Чем require отличается от require_relative?

    Ответ

    С возможностью указания абсолютного пути и относительного require подключает файлы/гемы по относительному пути в строгом соответствии ./1/ruby.rb, начиная с корня приложения require_relative подключает файлы без относительного пути и без указания разрешения файла, запускает прогу из той же директории, где лежит файл запуска require_relative '1/ruby.rb'.

    http://ruby.qkspace.com/ruby-require-require_relative

  9. Что такое гемы? Как с ними работать?

  10. Как создать геттер и сеттер методы в ruby?

    Ответ C помощью методов
    • attr_reader
    • attr_writer
    • attr_accessor — объединяет attr_reader и attr_writer
    class Tovar
      # Метод для установки цены
      def price=(price)
        @price = price
      end
    
      def price
        @price
      end
    end

    http://rubyclub.blogspot.com/2012/10/ruby_15.html

    http://findnerd.com/list/view/How-to-create-getter-and-setter-methods-in-Ruby/13615/

  11. Что такое attr_reader, attr_writer, attr_accessor?

    Ответ

    Все классы наследуют методы Module.

    attr_reader, attr_writer, attr_accessor являются его методами.

    Что делают эти методы внутри класса?

    attr_reader создаёт переменную экземпляра и метод-геттер, который возвращает её значение

    Эти записи эквивалентны:

    attr_reader :name
    
    def name
      @name
    end

    attr_writer создаёт метод-сеттер, позволяющий изменять переменную экземпляра.

    Эти записи эквивалентны:

    attr_writer :name
    
    def name=(name)
      @name = name
    end

    attr_accessor объединяет функционал attr_reader и attr_writer.

    http://ruby-doc.org/core-2.5.1/Module.html#method-i-attr_reader

    http://ruby-doc.org/core-2.5.1/Module.html#method-i-attr_writer

    http://ruby-doc.org/core-2.5.1/Module.html#method-i-attr_accessor

  12. Что означает ключевое слово self?

    Ответ

    self относится к самому объекту, вызывает сам себя, без создания класса. Обычно применяется к методам внутри класса, чтобы можно вызвать без создания нового экземпляра класса.

    Так же можно сообщить что все методы будут self, делается с помощью class << self.

  13. Что такое синглтон-методы и синглтон-классы?

    Ответ Синглтон-метод — метод, который может принадлежать только одному объекту. Это даёт возможность добавлять уникальное поведение отдельным объектам.
    cat = Animal.new
    dog = Animal.new
    
    def dog.barking
      'WOOF! WOOF!'
    end
    
    dog.barking
    # => "WOOF! WOOF!"
    dog.singleton_methods
    # => [:barking]
    
    cat.barking
    # => NoMethodError (undefined method `barking' for #<Animal:0x000055a12143df38>)
    cat.singleton_methods
    # => []

    Методы класса (self-методы) на самом деле тоже являются синглтон-методами класса Class.

    Таким образом, в Руби все методы принадлежат какому-то классу.

    Синглтон-класс — это анонимный класс, в котором размещаются синглтон-методы объекта.

    dog.singleton_class
    # => #<Class:#<Animal:0x000055a121433970>>
    
    dog.singleton_class.method_defined?(:barking)
    # => true
    
    cat.singleton_class.method_defined?(:barking)
    # => false

    Синглтон-класс встраивается в путь наследования и поиска метода интерпретатором Ruby.

    dog.singleton_class.superclass
    # => Animal

    Подробнее тут

  14. Что такое super-методы и как они работают/где применяются?

  15. Что такое модуль в ruby? Какая разница между классом и модулем?

    Ответ Модули в Руби похожи на классы в том, что они содержат набор методов, константы, другие модули и определения классов.

    Модули задаются как классы, только слово module используется вместо class.

    В отличие от классов создать объекты на основе модуля нельзя, модуль не может иметь подклассы. Вместо этого вы добавляете недостающую функциональность класса или отдельного объекта с помощью модуля.

    Модули — одиночки, нет иерархии и наследования.

    https://habr.com/post/49353/

  16. Как организовано наследование в Ruby?

    Ответ

    Наследование в Ruby — прямое. У каждого класса может быть только один родительский класс.

    Синтаксический сахар:

    class Animal
    end
    
    class Dog < Animal
    end

    В Ruby всё в конечном счёте принадлежит классу BasicObject.

    str = "Я - строка"
    str.class #=> String
    str.class.superclass #=> Object
    str.class.superclass.superclass #=> BasicObject

    Однако в Ruby можно сымитировать множественное наследование с помощью модулей, подключая их при помощи include/extend.

  17. Чем отличается include от extend? Что такое prepend?

    Ответ
    • include — необходимо создать экземпляр класса, чтобы задействовать логику модуля;
    • extend — позволяет включить дополнительное расширение или функциональность без создания экземпляра класса, непосредственно в используемом классе.

    https://habr.com/post/143483/

    https://inet777.ru/comments/8436/metod-module-prepend-v-ruby-2

    C помощью prepend методы модуля устанавливаются первоочередными при поиске метода в классе, в который включен модуль.

  18. Реализация множественного наследования в ruby?

    Ответ

    Реализация возможна через модули с помощью подключения include/extend.

  19. Какие есть способы вызова методов в ruby?

    Ответ
    • .call — не может вызвать методы без нового класса

    • .send — может вызвать методы без нового класса

    • .eval — не используется, так как очень медленный http://quabr.com/35400337/ruby-send-vs-call-method

  20. Что такое proc, lambda, block? И какие отличия есть между ними?

    Ответ Это анонимные функции, которые представляют из себя блоки.

    lambda требует чтобы кол-во аргументов в блоке, соответствовало преданным в блок, так же lambda возвращает значение без блока, можно вызвать на переменной метод call и передать к примеру return 'any', lambda выведет.

    proc не требует и может работать без передачи аргументов, но не может вызваться методом call и вернуть переданное значение методом return.

    block это кусочек ruby кода, который заключен в фигурные скобки и блок выполняется для каждого массива значений.

  21. Многопоточность в ruby?

  22. Какие сервера бывают под Ruby?

    Ответ

    https://www.8host.com/blog/kratkij-obzor-veb-serverov-dlya-prilozhenij-ruby/

    • WeBrick
    • Phusion Passenger
    • Puma
    • Thin
    • Unicorn
    • Iodine
  23. Что такое safe navigation?

    Ответ

    В новом синтаксисе выражение из примеров можно записать так:

    image = user&.profile&.thumbnails&.large

    Оператор применяется для сокращения выражений, где выполняется проверка существования объекта и затем обращение к методу объекта только в случае положительной проверки:

    obj.nil? && obj.some_method

    Вместе с лаконичным видом такая реализация дает быструю проверку на nil, так как изменения реализованы на уровне парсера и ruby-код в проверках не участвует. После того, как встретился nil, дальнейшее выполнение цепочки прерывается. Проверка выполняется именно на nil, а не на логическое условие, поэтому если результатом окажется false, то выполнение будет успешно продолжено по цепочке дальше.

    Если в метод передаются аргументы, то, в отличие от try, они вычисляются только в том случае, если объект существует и метод реально вызывается. Например, для ActiveSupport в выражении obj.try(:foo, bar()) всегда будет выполняться bar(), даже если obj не существует. Но в выражении obj&.foo(bar()), аргумент bar() будет вычислен только тогда, когда obj не равен nil.

    http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/

    https://www.competa.com/blog/ruby-safe-navigation-operator-methods/

    https://habr.com/ru/company/truevds/blog/271301/

    https://medium.com/@CohenCarlisle/why-you-shouldnt-be-using-rails-try-for-nil-safe-navigation-in-ruby-d3123a3965ac

  24. Как и чем проверить скорость работы методов? К примеру, что работает быстрее each, proc или lambda?

    Ответ

    Существуют гемы для сравнения скорости работы методов, например, benchmark-ips.

    С учётом особенностей синтаксиса гема пишется код, в котором тестируются выбранные методы. При запуске программа тестируют производительность методов с указанием разницы в процентах. https://github.com/evanphx/benchmark-ips

  25. Если в модуле сделать extend self что произойдет?