Про які Ruby Gotchas слід попередити новачка? [зачинено]


108

Я нещодавно вивчив мову програмування Ruby, і загалом це гарна мова. Але я був дуже здивований, побачивши, що це не так просто, як я очікував. Точніше, «правило найменшого здивування» мені не здавалося дуже дотриманим (звичайно це досить суб’єктивно). Наприклад:

x = true and false
puts x  # displays true!

і відомі:

puts "zero is true!" if 0  # zero is true!

Які ще "Gotchas" ви б попередили новачка Рубі?


@ phrases.insert (0, p) Гаразд @ phrases.insert (p) НІЧОГО не відбувається @phrases << p # ОК
Anno2001

чому true and falseповертається правда?
Юрген Пол

3
Тому що "x = правда і хибність" насправді трактується як "(x = істина) і false". Це питання пріоритету оператора: "і" має нижчий пріоритет, ніж "=". Більшість інших мов мають зворотний пріоритет, я не знаю, чому вони обрали цей порядок у Rails, я вважаю це дуже заплутаним. Якщо ви хочете "нормальної" поведінки, просто введіть "x = (справжнє та хибне)", тоді x буде хибним.
MiniQuark

4
Іншим рішенням є використання "&&" та "||" замість "і" і "або": вони поводяться так, як очікувалося. Наприклад: "x = true && false" призводить до того, що x є хибним.
MiniQuark

"Принцип найменшого сюрпризу означає принцип щонайменше мого здивування". від en.wikipedia.org/wiki/Ruby_(programming_language)## Філософія Те саме стосується і Python. У мене були подібні цитати про творця Python, але я забуваю, де це було.
Darek Nędza

Відповіді:


59

Вікіпедія Рубі

Зі статті:

  • Імена, які починаються з великої літери, трактуються як константи, тому локальні змінні повинні починатися з малої літери.
  • Символи $та @не вказують змінний тип даних, як у Perl, а швидше функціонують як оператори роздільної здатності.
  • Для позначення чисел з плаваючою комою слід слідувати нульовій цифрі ( 99.0) або явному перетворенню ( 99.to_f). Додавання крапки недостатньо (99. ) , оскільки числа чутливі до синтаксису методу.
  • Булева оцінка не-логічних даних є строгим: 0, ""і []все оцінені з true. В C вираз 0 ? 1 : 0оцінюється на 0(тобто хибне). Однак у Ruby це дає результат 1, як оцінюють усі числа true; тільки nilі falseоцінювати false. Наслідком цього правила є те, що методи Ruby шляхом домовленості - наприклад, пошук у регулярному виразі - повертають числа, рядки, списки чи інші не хибні значення на успіх, але nilна неуспіх (наприклад, невідповідність). Ця умова використовується також у Smalltalk, де лише спеціальні об'єкти trueі falseможуть бути використані в булевому виразі.
  • У версіях до 1.9 відсутні типи даних для символів (порівняйте з C, який надає тип charсимволів). Це може спричинити сюрпризи при нарізанні рядків: "abc"[0]урожайність 97(ціле число, що представляє ASCII код першого символу в рядку); отримати "a"використання "abc"[0,1](підрядок довжиною 1) або"abc"[0].chr .
  • Позначення statement until expression, на відміну від еквівалентних висловлювань інших мов (наприклад, do { statement } while (not(expression));у C / C ++ / ...), насправді ніколи не запускає оператор, якщо вираз уже є true. Це тому statement until expression, що насправді синтаксичний цукор закінчився

    until expression
      statement
    end

    , еквівалент якого в C / C ++ так while (not(expression)) statement;само, як statement if expressionеквівалент

    if expression
      statement
    end

    Однак позначення

    begin
      statement
    end until expression

    насправді у Ruby буде запущено твердження один раз, навіть якщо вираз уже правдивий.

  • Оскільки константи є посиланнями на об'єкти, зміна того, на яку посилається константа, генерує попередження, але зміна самого об'єкта не робить. Наприклад, Greeting << " world!" if Greeting == "Hello"не генерує помилку чи попередження. Це схоже на finalзмінні в Java, але у Ruby також є функціонал для "заморожування" об'єкта, на відміну від Java.

Деякі функції, які особливо відрізняються від інших мов:

  • Звичайні оператори для умовних виразів, andпричому or, не дотримуються нормальних правил пріоритетності: andне пов'язує більш жорсткі, ніж or. Рубін також оператори вираження ||і &&які працюють , як і очікувалося.

  • defвсередині defне робиться того, чого може очікувати програміст Python:

    def a_method
        x = 7
        def print_x; puts x end
        print_x
    end

    Це дає помилку щодо xне визначеності. Вам потрібно використовувати a Proc.

Мовні особливості

  • Опущення дужок навколо аргументів методу може призвести до несподіваних результатів, якщо методи приймають кілька параметрів. Розробники Ruby заявили, що у майбутніх версіях Ruby упущення круглих дужок на багатопараметричні методи може бути заборонено; нинішній (листопад 2007 р.) перекладач Ruby видає попередження, яке закликає письменника не упускати (), щоб уникнути неоднозначного значення коду. Невикористання ()все ще є звичайною практикою, і може бути особливо приємно використовувати Ruby як зрозумілу людину мову програмування, специфічну для домену, поряд з методом, який називається method_missing().

1
У Ruby 1.9 також відсутній тип даних символів. У 1.8 індексний оператор повернув Fixnum; в 1.9 він еквівалентний нарізці односимвольних рядків.
whitequark

38

У новачків виникнуть проблеми з методами рівності :

  • a == b : перевіряє, чи a і b рівні. Це найкорисніше.
  • a.eql? б : також перевіряє, чи a і b рівні, але іноді це суворіше (можливо, перевіряють, наприклад, що a і b мають один і той же тип). В основному використовується в хешах.
  • a.equal? б : перевіряє, чи є a і b однаковим об'єктом (перевірка ідентичності).
  • a === b : використовується у висловлюваннях випадків (я читаю це як " відповідність b ").

Ці приклади повинні уточнити перші 3 способи:

a = b = "joe"

a==b       # true
a.eql? b   # true
a.equal? b # true (a.object_id == b.object_id)

a = "joe"
b = "joe"

a==b       # true
a.eql? b   # true
a.equal? b # false (a.object_id != b.object_id)

a = 1
b = 1.0

a==b       # true
a.eql? b   # false (a.class != b.class)
a.equal? b # false

Зауважте, що == , eql? і рівний? завжди має бути симетричним: якщо a == b, то b == a.

Також зауважте, що == і eql? обидва реалізовані в класі Object як псевдоніми рівним? , тож якщо ви створюєте новий клас і хочете == та eql? щоб означати щось інше, ніж звичайна ідентичність, тоді вам потрібно перекрити їх обох. Наприклад:

class Person
    attr_reader name
    def == (rhs)
      rhs.name == self.name  # compare person by their name
    end
    def eql? (rhs)
      self == rhs
    end
    # never override the equal? method!
end

Метод === поводиться по-різному. Перш за все це не симетрично (a === b не означає, що b === a). Як я вже сказав, ви можете прочитати a === b як "відповідність b". Ось кілька прикладів:

# === is usually simply an alias for ==
"joe" === "joe"  # true
"joe" === "bob"  # false

# but ranges match any value they include
(1..10) === 5        # true
(1..10) === 19       # false
(1..10) === (1..10)  # false (the range does not include itself)

# arrays just match equal arrays, but they do not match included values!
[1,2,3] === [1,2,3] # true
[1,2,3] === 2       # false

# classes match their instances and instances of derived classes
String === "joe"   # true
String === 1.5     # false (1.5 is not a String)
String === String  # false (the String class is not itself a String)

Опис справи складається на основі методу === :

case a
  when "joe": puts "1"
  when 1.0  : puts "2"
  when (1..10), (15..20): puts "3"
  else puts "4"
end

еквівалентно цьому:

if "joe" === a
  puts "1"
elsif 1.0 === a
  puts "2"
elsif (1..10) === a || (15..20) === a
  puts "3"
else
  puts "4"
end

Якщо визначити новий клас , чиї екземпляри є свого роду контейнер або діапазону (якщо у нього є що - щось на зразок ? Включають або ? Сірник метод), то ви можете знайти його корисним перевизначити === метод , як це:

class Subnet
  [...]
  def include? (ip_address_or_subnet)
    [...]
  end
  def === (rhs)
    self.include? rhs
  end
end

case destination_ip
  when white_listed_subnet: puts "the ip belongs to the white-listed subnet"
  when black_listed_subnet: puts "the ip belongs to the black-listed subnet"
  [...]
end

1
Також: a = 'строка'; b = 'строка'; pa == b; a = a.force_encoding 'ASCII-8BIT'; b = b.force_encoding 'UTF-8'; pa == b; pa === b; p a.eql? б; p a.equal? б
Накілон

20
  • Накладення мавп . У Ruby є відкриті класи, тому їх поведінку можна динамічно змінювати під час виконання ...

  • Об'єкти можуть реагувати на невизначені методи, якщо method_missingабо sendбули відмінені. Це використовує виклик методу на основі повідомлення Рубі. Rails ' ActiveRecord система використовує це з великим ефектом.


18

Наступний код мене здивував. Я думаю, що це небезпечна прихильність: як легко натрапити на, так і важко налагодити.

(1..5).each do |number|
  comment = " is even" if number%2==0
  puts number.to_s + comment.to_s
end

Це відбитки:

1
2 is even
3
4 is even
5

Але якщо я просто додати comment =щось перед блоком ...

comment = nil
(1..5).each do |number|
  comment = " is even" if number%2==0
  puts number.to_s + comment.to_s
end

Тоді я отримую:

1
2 is even
3 is even
4 is even
5 is even

В основному, коли змінна визначається лише всередині блоку, вона знищується в кінці блоку, а потім вона скидається nilна кожну ітерацію. Це зазвичай ви очікуєте. Але якщо змінна є визначена перед блоком, то зовнішня змінна використовується всередині блоку, і його значення , отже , зберігаються між ітерацій.

Одним із рішень було б написати це замість:

comment = number%2==0 ? " is even" : nil

Я думаю, що багато людей (включаючи мене) прагнуть написати " a = b if c" замість " a = (c ? b : nil)", тому що це читабельніше, але, очевидно, це має побічні ефекти.


4
Ви можете так само затінити змінну зовнішньої області на (1..5) do | number; comment | ..... Читайте тут stackoverflow.com/questions/1654637/…
Özgür

6
Мені це здається логічним. Цей обсяг є типовим для інших мов, саме синтаксис відрізняється.
г.

Однак ви можете написати, a = (b if c)щоб отримати бажаний ефект, без тернару. Це тому, що b if cоцінюється на нуль, якщо cце фальси.
Камерон Мартін

16

При виклику superбез аргументів переопределений метод насправді викликається тими ж аргументами, що і метод переопределення.

class A
  def hello(name="Dan")
    puts "hello #{name}"
  end
end

class B < A
  def hello(name)
    super
  end
end

B.new.hello("Bob") #=> "hello Bob"

Щоб насправді зателефонувати superбез аргументів, потрібно сказати super().


3
Якщо це B#helloбуло name = 42раніше super, то воно говорить "привіт 42".
Ендрю Грімм

14

Блоки та методи повертають значення останнього рядка за замовчуванням. Додавання putsзаяв до кінця для налагодження може спричинити неприємні побічні ефекти



11

У мене було багато проблем з розумінням змінних класів, атрибутів класу та методів класу. Цей код може допомогти новачку:

class A
  @@classvar = "A1"
  @classattr = "A2"
  def self.showvars
    puts "@@classvar => "+@@classvar
    puts "@classattr => "+@classattr
  end
end

A.showvars
  # displays:
  # @@classvar => A1
  # @classattr => A2

class B < A
  @@classvar = "B1"
  @classattr = "B2"
end

B.showvars
  # displays:
  # @@classvar => B1
  # @classattr => B2

A.showvars
  # displays:
  # @@classvar => B1   #Class variables are shared in a class hierarchy!
  # @classattr => A2   #Class attributes are not

1
Так, змінні класу можуть бути складними. Я думаю, що більшість досвідчених рубістів скажуть, що розумно їх уникати, оскільки зазвичай існують інші способи вирішити проблему без них. Деякі ентузіасти мови навіть кажуть, що змінні класи Рубі погано розроблені на мовному рівні.
Девід Дж.

8

одне, що я навчився - це обережно користуватися оператором || =. і будьте особливо обережні, якщо ви маєте справу з булевими. Я зазвичай використовував || = b як спіймання всіх, щоб дати "a" значення за замовчуванням, якщо все інше не вдалося, а "a" залишилося нульовим. але якщо a є хибним, а b - істинним, тоді заповіту буде присвоєно істину.


Ви можете використовувати a = b if a.nil?або @a = b unless defined?(@a).
Ендрю Грімм

8
  • Блоки дійсно важливі для розуміння, вони використовуються всюди.

  • Не потрібні дужки навколо параметрів методу. Незалежно від того, користуєтесь ви ними чи ні, не залежить від вас. Деякі кажуть, що завжди слід їх використовувати .

  • Використовуйте піднімання та порятунок для поводження з винятками, а не кидання та ловлення.

  • Ви можете використовувати, ;але не потрібно, якщо ви не хочете ставити кілька речей в один рядок.


Якщо ви не плануєте виходити за межі Ruby 1.8.6, тоді ігноруйте паролі стільки, скільки вам подобається. Інакше вам, мабуть, краще використовувати їх.
Майк Вудхаус

7

У мене виникли проблеми із змішами, які містять методи екземпляра та методи класу. Цей код може допомогти новачку:

module Displayable
  # instance methods here
  def display
    puts name
    self.class.increment_displays
  end
  def self.included(base)
    # This module method will be called automatically
    # after this module is included in a class.
    # We want to add the class methods to the class.
    base.extend Displayable::ClassMethods
  end
  module ClassMethods
    # class methods here
    def number_of_displays
      @number_of_displays # this is a class attribute
    end
    def increment_displays
      @number_of_displays += 1
    end
    def init_displays
      @number_of_displays = 0
    end
    # this module method will be called automatically
    # after this module is extended by a class.
    # We want to perform some initialization on a
    # class attribute.
    def self.extended(base)
      base.init_displays
    end
  end
end

class Person
  include Displayable
  def name; @name; end
  def initialize(name); @name=name; end
end

puts Person.number_of_displays # => 0
john = Person.new "John"
john.display # => John
puts Person.number_of_displays # => 1
jack = Person.new "Jack"
jack.display # => Jack
puts Person.number_of_displays # => 2

Спочатку я думав, що я можу мати модулі як з методами екземпляра, так і з методами класу, просто зробивши це:

module Displayable
  def display
    puts name
    self.class.increment_displays
  end
  def self.number_of_displays  # WRONG!
    @number_of_displays
  end
  [...]
end

На жаль, метод number_of_displays ніколи не буде включений або розширений, оскільки це "метод класового модуля". Лише "методи екземпляра модуля" можуть бути включені до класу (як методи екземпляра) або розширені до класу (як методи класу). Ось чому вам потрібно помістити методи екземпляра вашого mixin в модуль, а методи вашого класу mixin в інший модуль (ви зазвичай кладете методи класу в підмодуль «ClassMethods»). Завдяки включеному магічному методу, ви можете полегшити включення як методів екземпляра, так і методів класу лише в один простий дзвінок "включити відображуваний" (як показано в прикладі вище).

Цей міксин буде рахувати кожен дисплей на основі кожного класу . Лічильник - це атрибут класу, тому у кожного класу буде свій власний (ваша програма, ймовірно, вийде з ладу, якщо ви виведете новий клас із класу Person, оскільки лічильник @number_of_displays для похідного класу ніколи не буде ініціалізований). Ви можете замінити @number_of_displays на @@ number_of_displays, щоб зробити його глобальним лічильником. У цьому випадку для кожної ієрархії класів буде свій лічильник. Якщо ви хочете глобальний та унікальний лічильник, вам, ймовірно, слід зробити його атрибутом модуля.

Все це для мене точно не було інтуїтивно зрозумілим, коли я починав з Рубі.

Я все ще не можу зрозуміти, як можна чітко зробити деякі з цих методів mixin приватними або захищеними (лише публічні методи повинні включатись лише метод відображення та число_офіцій .


7

Зверніть увагу на позначення діапазону.

(Принаймні, зверніть більше уваги, ніж я спочатку робив!)

Існує різниця між 0..10 (дві крапки) і 0...10(три крапки).

Мені дуже подобається Рубі. Але ця річ із крапкою та крапкою переживає мене. Я думаю, що така тонка двосинтаксична "особливість", що є:

  • легко вводити текст і
  • легко пропустити очима, оглядаючи код

не повинно бути здатним викликати руйнівні помилки один за одним у моїх програмах.


1
Не сильно відрізняється від for (i=0; i<max; i++)іfor (i=0; i<=max; i++)
g.

Я намагався з'ясувати, у чому різниця між 0..10 та 0 ... 10.
Луїс Д Уррака

6

Я думаю, що " and" і " or" кивають на Перла, який є одним із очевидних "батьків" Рубі (найвидатнішим іншим є Smalltalk). Вони обидва мають набагато нижчий пріоритет (нижче ніж поступки, насправді, що , коли поведінка відзначено походить від) , ніж &&та ||які операторів ви повинні використовувати.

Інші речі, про які слід пам’ятати, не відразу очевидні:

Ви дійсно не називаєте методи / функції, хоча це виглядає так. Натомість, як і у Smalltalk, ви надсилаєте повідомлення об’єкту. Так method_missingсправді більше схоже message_not_understood.

some_object.do_something(args)

еквівалентно

some_object.send(:do_something, args) # note the :

Символи дуже широко використовуються. Це те, що починається з того, :і вони не відразу очевидні (ну, вони мені не були), але чим раніше ви з ними стикаєтеся, тим краще.

Рубі є великим в «типі качки», слідкуючи за принципом, що «якщо він ходить як качка, і трясеться, як качка ...», що дозволяє неформальну підміну предметів загальним підмножиною методів без явного успадкування чи взаємодії міксина.


Дякую. Є одне, чого я ненавиджу щодо методу надсилання : він дозволяє викликати приватні методи навіть поза класом! Ой.
MiniQuark

1
@MiniQuark: саме це мені подобається у способі відправки!
Ендрю Грімм

6

Якщо ви оголосили сеттера (ака мутатора) за допомогою attr_writerабо attr_accessor(або def foo=), будьте обережні, викликаючи його зсередини класу. Оскільки змінні декларовано неявно, інтерпретатору завжди доводиться вирішувати foo = barяк оголошення нової змінної з ім'ям foo, а не викликати метод self.foo=(bar).

class Thing
  attr_accessor :foo
  def initialize
    @foo = 1      # this sets @foo to 1
    self.foo = 2  # this sets @foo to 2
    foo = 3       # this does *not* set @foo
  end
end

puts Thing.new.foo #=> 2

Це стосується також об'єктів Rails ActiveRecord, які визначають доступних користувачів на основі полів у базі даних. Оскільки вони навіть не є перемінними екземплярами @ -style, правильний спосіб встановити ці значення окремо - з self.value = 123або self['value'] = 123.


5

Розуміння різниці між класом Час і Дата. Обидва різні та створили проблеми під час використання їх у рейках. Часовий клас іноді суперечить іншим бібліотекам часового класу, присутнім у стандартній бібліотеці рубінів / рейок. Особисто мені знадобилося багато часу, щоб зрозуміти, що саме відбувається в моєму додатку рейки. Пізніше я зрозумів, коли це зробив

Time.new

Це стосувалося якоїсь бібліотеки в такому місці, про яке я навіть не знав.

Вибачте, якщо мені не зрозуміло, що саме я хочу сказати. Якщо інші стикалися з подібними проблемами, будь ласка, поясніть їх.


4

Одне, що мене зловило в минулому, - це те, що \nпослідовність виходу символів нового рядка ( ) серед інших - не підтримується рядками в рамках одного лапки. Зворотна косою рисою сама втеча. Ви повинні використовувати подвійні лапки для втечі, щоб працювати, як очікувалося.


1
І що відрізняється від іншої мови?
Роберт Гембл

Ява, для одного. Одиночні лапки в Java можна використовувати лише для додавання одного символу, а не для Strings.
Джон Топлі

1
Це відповідає будь-якій мові, яка дозволяє використовувати окремі лапки для рядків, і саме тому вони роблять.
сінгполіма

@John: правда, але "\ n" у Java все ще буде символом нового рядка.
Джорн

1
Але в Java одиничні лапки створюють лише значення типу char. Не струни. Ось і різниця.
jmucchiello

4
x = (true and false) # x is false

0 і "" є істинними, як ви вказали.

Ви можете мати метод і модуль / клас з тим самим іменем (що має сенс, оскільки метод насправді додається до Object і, таким чином, має власний простір імен).

Немає багаторазового успадкування, але часто "змішані модулі" використовуються для додавання загальних методів до декількох класів.


0 == true // argh, компілятор c в моєму мозку вибухає !!
kenny

1
0 == true дає false в Ruby. Це 0 правда має сенс, тому що true - це об'єкт у Ruby. У C 0 просто трапляється таке ж представлення, що і false.
Жуль

У стані в Рубі, тільки falseі nilє хибними. Усі інші - справжні цінності.
rubyprince

4

Методи можуть бути переосмислені і можуть стати розумними, поки не з’ясуємо причину. ( Правда, цю помилку, мабуть, дещо важче виявити, коли дії контролера Ruby on Rails повторно визначаються помилково! )

#demo.rb
class Demo

  def hello1
    p "Hello from first definition"
  end

  # ...lots of code here...
  # and you forget that you have already defined hello1

  def hello1
    p "Hello from second definition"
  end

end
Demo.new.hello1

Виконати:

$ ruby demo.rb
=> "Hello from second definition"

Але зателефонуйте з увімкненими попередженнями, і ви побачите причину:

$ ruby -w demo.rb
demo.rb:10: warning: method redefined; discarding old hello1
=> "Hello from second definition"

Я б +100 використовував попередження, якби міг.
Ендрю Грімм

3

Я думаю, що завжди корисно використовувати .length для речей ... оскільки розмір підтримується майже всім, а у Ruby є динамічні типи, ви можете отримати дійсно дивні результати виклику .size, коли у вас неправильний тип ... a NoMethodError: невизначений метод `length ', тому я зазвичай ніколи не називаю розмір об'єктів у Ruby.

покусав мене не раз.

Також пам’ятайте, що об’єкти мають ідентифікатори, тому я намагаюся не використовувати змінні виклики id або object_id, щоб уникнути плутанини. Якщо мені потрібен ідентифікатор об’єкта Users, найкраще назвати його на зразок user_id.

Всього два мої центи


2

Я новачок у рубіні, і під час першого раунду я потрапив на проблему щодо зміни плавців / рядків на ціле число. Я почав з поплавців і все закодував f.to_int . Але коли я продовжував і використовував той самий метод для рядків, мене викинула крива, коли вона запускала програму.

Судячи з усього, рядок не має методу to_int , але плаває і ints.

irb(main):003:0* str_val = '5.0'
=> "5.0"
irb(main):006:0> str_val.to_int
NoMethodError: undefined method `to_int' for "5.0":String
        from (irb):6
irb(main):005:0* str_val.to_i
=> 5


irb(main):007:0> float_val = 5.0
=> 5.0
irb(main):008:0> float_val.to_int
=> 5
irb(main):009:0> float_val.to_i
=> 5
irb(main):010:0>

Довільні дужки кинули мене і спочатку. Я бачив якийсь код із, а якийсь без. Мені знадобилося деякий час, щоб зрозуміти, що будь-які стилі прийняті.


2

Пов'язаний з відповіддю монкута, Рубі to_foo методи натякають, наскільки суворо перетворення вони будуть робити.

Короткі, як-от to_i, to_sскажіть, що вони ледачі, і перетворіть їх у цільовий тип, навіть якщо вони не можуть бути точно представлені у такому форматі. Наприклад:

"10".to_i == 10
:foo.to_s == "foo"

Більш довгі явні функції, такі як to_int, to_sозначають, що об'єкт може бути представлений як тип даних. Наприклад, Rationalклас представляє всі раціональні числа, тому його можна безпосередньо представити у вигляді цілого числа Fixnum (або Bignum) шляхом виклику to_int.

Rational(20,4).to_int == 5

Якщо ви не можете викликати більш довгий метод, це означає, що об'єкт не може бути представлений у цьому типі.

Отже, при перетворенні, якщо ви лінуєтесь з іменами методів, Ruby буде ледачим з перетворенням.


1
Чи тут правильне слово "ледачий"?
Ендрю Грімм


1

Ітерація над рубіновими хешами не гарантується в будь-якому конкретному порядку. (Це не помилка, це особливість)

Hash#sort корисно, якщо вам потрібно певне замовлення.

Пов'язане питання: Чому масив Рубі з 1000 хеш-клав і значень пар завжди в певному порядку?


4
це не вірно з 1.9: "Однак у Ruby 1.9, хеш-елементи повторюються в порядку їх вставки" з мови програмування Ruby
13.08.10

0

Один раз мене змучив:

1/2 == 0.5 #=> false
1/2 == 0   #=> true

Я вважаю, що це було б так само в Java, C та C ++.
Ларрі

Це смішно, я навіть не думав про це, але якщо ви відкриєте irb і спробуйте це, має сенс: Отже (1/2) - це Fixnum, а (0,5) - Float. І ми знаємо, що Fixnim! = Пливе.
DemitryT

2
@DemitryT Я думаю, що простішою причиною є те, що 1/2оцінюється 0, що не дорівнює 0.5, незалежно від типу. Однак Rational(1, 2) == 0.5, і 1.0 == 1.
Макс Нанасі

універсальна мовна гикавка тут. це щось, про що повинен знати рубін І програмування.
dtc

0
1..5.each {|x| puts x}

не працює. Ви повинні поставити діапазон у круглі дужки, як

(1..5).each {|x| puts x}

тож не здається, що ти дзвониш 5.each. Я думаю, що це питання пріоритету, як і x = true and falseґетча.


Я б назвав це скобками. По-друге, якщо якийсь код схожий на те, що має значення повернення / пріоритет, він все одно повинен бути оточений дужками. Отже, для мене немає нічого особливого на цій «ґутчі». Ви можете продовжувати писати всі комбінаційні "ґетчі", однак це буде марною тратою часу. Чесно кажучи, навіть якщо ви мали очікуваний результат з цього приводу, я все-таки вважаю за краще оточення з дужками.
Özgür
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.