Skip to content

Latest commit

 

History

History
751 lines (498 loc) · 35.6 KB

ruby.md

File metadata and controls

751 lines (498 loc) · 35.6 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. Как хранится массив в памяти?

  3. Какую структуру данных применить для проверки "парности скобок" вида ([]) и ([[))?

  4. Почему в Ruby 1660 / 100 ≠ 16.6?

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

    Таким образом, чтобы получить 16.6 нужно чтобы одно из чисел имело тип Float.

    https://stackoverflow.com/questions/5502761/why-is-division-in-ruby-returning-an-integer-instead-of-decimal-value

  5. Почему в Ruby 24.0 * 0.1 ≠ 2.4?

    Ответ Поскольку внутренне компьютеры используют формат (binary floating point), который не может точно представить число как 0.1, 0.2 или 0.3.

    Когда код компилируется или интерпретируется, ваш «0.1» уже округляется до ближайшего числа в этом формате, что приводит к небольшой ошибке округления даже до того, как произойдет вычисление.

    https://floating-point-gui.de/basic/

    https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#floats_imprecise

    https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems

  6. Какие структуры есть в 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}"
  7. Что такое 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

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

    Ответ

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

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

    Ответ

    Циклы until, for

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

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

  10. Назовите отличия inject и reduce.

    Ответ

    Это алиасы.

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

    Ответ

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

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

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

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

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

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

    Ответ

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

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

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

    Ответ

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

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

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

  15. Как создать геттер и сеттер методы в 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/

  16. Что такое 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

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

    Ответ

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

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

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

    Ответ Синглтон-метод — метод, который может принадлежать только одному объекту. Это даёт возможность добавлять уникальное поведение отдельным объектам.
    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

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

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

    Ответ `super` - ключевое слово, вызывает из родительского класса метод с аналогичным названием, что и метод вызывающий `super`. Применяется при переопределинии методов в дочерних классах.
      class Text
        def initialize(body:)
          @body = body
        end
      end
    
      class Note < Text
        def initialize(body:)
          super
          @date = Time.now
        end
      end
    
      # Если количество параметров в методе родительского и дочернего классов не совпадает
      # можно явно задать аргументы ключевому слову super
      class Article < Text
        def initialize(body:, title:)
          super(body: body) # Явное задание количества аргументов для  super
          @title = title
        end
      end
    
      text = Text.new(body: 'Просто текст')
      note = Note.new(body: 'Заметка')
      article = Article.new(title: 'Статья', body: 'Текст статьи')
    
      p text      #<Text:0x0000559cc64f3590 @body="Просто текст">
      p note      #<Note:0x0000559cc64f32e8 @body="Заметка", @date=2021-05-05 21:58:38.829037856 +0500>
      p article   #<Article:0x0000559cc64f2e60 @body="Текст статьи", @title="Статья">
    
    
  20. Что такое модуль в ruby? Какая разница между классом и модулем?

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

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

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

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

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

  21. Как организовано наследование в 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.

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

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

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

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

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

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

    Ответ

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

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

    Ответ

    Как указано выше, extend позволяет подключить методы модуля к классу без создания экземпляра.

    Для модуля self — это сам модуль.

    Поэтому добавление extend self позволит использовать инстанс-методы модуля в качестве его self-методов.

    Без extend self:

    module MyModule
      def my_method
        puts 'Hello!'
      end
    end
    
    MyModule.my_method
    
    # undefined method `my_method' for MyModule:Module (NoMethodError)

    После добавления:

    module MyModule
      extend self
    
      def my_method
        puts 'Hello!'
      end
    end
    
    MyModule.my_method
    
    # Hello!

    https://blog.bigbinary.com/2012/06/28/extend-self-in-ruby.html#so-how-does-extend-self-work

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

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

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

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

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

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

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

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

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

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

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

    Ответ

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

    • WeBrick
    • Phusion Passenger
    • Puma
    • Thin
    • Unicorn
    • Iodine
  29. Что такое 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

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

    Ответ

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

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

  31. Какие существуют Ruby интерпретаторы?

    Ответ
    • CRuby
    • MRI
    • JRuby (MRi на базе JVM)
    • Rubinius (реализация многопоточности на самом Ruby, достаточно успешная, но не без сайдэффектов)
    • TruffleRuby

    https://habr.com/ru/post/337100/

  32. Что такое JIT?

    Ответ Just-In-Time (JIT) компиллятор оптимизирует, часто вызываемые методы. Таким образом, они будут запускаться быстрее в последующих вызовых. Главная цель JIT - это пропуск нескольких или всех шагов интерпретации.

    https://blog.heroku.com/ruby-just-in-time-compilation https://ru.wikipedia.org/wiki/JIT-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F https://www.youtube.com/watch?v=AJIAMT7ilHw

  33. Какую сортировку использует метод sort в ruby?