Я недавно выучил язык программирования Ruby, и в целом это хороший язык. Но я был весьма удивлен, увидев, что все оказалось не так просто, как я ожидал. Точнее, «правило наименьшего удивления» мне показалось не очень уважаемым (конечно, это довольно субъективно). Например:
x = true and false
puts x # displays true!
и знаменитые:
puts "zero is true!" if 0 # zero is true!
О каких еще проблемах вы бы предупредили новичка в Ruby?
true and false
возвращается истина?Ответы:
Википедия, подводные камни Ruby
Из статьи:
$
и@
не указывают тип данных переменных, как в 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
.char
для символов). Это может вызвать сюрпризы при нарезке строк:"abc"[0]
yields97
(целое число, представляющее код ASCII первого символа в строке); чтобы получить"a"
использование"abc"[0,1]
(подстрока длины 1) или"abc"[0].chr
.Нотация
statement until expression
, в отличие от эквивалентных операторов других языков (например,do { statement } while (not(expression));
в C / C ++ / ...), фактически никогда не запускает оператор, если выражение уже естьtrue
. Это потому, чтоstatement until expression
на самом деле синтаксический сахар, эквивалент которого в C / C ++ такой
while (not(expression)) statement;
же, какstatement if expression
и эквивалентОднако обозначение
в Ruby фактически выполнит оператор один раз, даже если выражение уже истинно.
Greeting << " world!" if Greeting == "Hello"
не выдает ошибку или предупреждение. Это похоже наfinal
переменные в Java, но в Ruby также есть возможность «заморозить» объект, в отличие от Java.Некоторые функции, которые заметно отличаются от других языков:
Обычные операторы для условных выражений
and
иor
не следуют обычным правилам приоритета:and
не связывает более жестко, чемor
. Рубин также операторы выражения||
и&&
которые работают , как и ожидалось.def
insidedef
не делает того, чего может ожидать программист Python:Это дает ошибку о том, что
x
не определено. Вам нужно использоватьProc
.Особенности языка
()
, чтобы избежать неоднозначного значения кода. Отказ от использования()
по-прежнему является обычной практикой, и может быть особенно полезно использовать Ruby как сам читаемый предметно-ориентированный язык программирования вместе с вызываемым методомmethod_missing()
.источник
У новичков будут проблемы с методами равенства :
Эти примеры должны прояснить первые 3 метода:
Обратите внимание, что == , eql? и равный? всегда должен быть симметричным: если a == b, то b == a.
Также обратите внимание, что == и eql? оба реализованы в классе Object как равные псевдонимы ? , так что если вы создаете новый класс и хотите == и eql? для обозначения чего-то другого, кроме простой идентичности, вам необходимо переопределить их оба. Например:
Метод === ведет себя иначе. Прежде всего, он не симметричен (a === b не означает, что b === a). Как я уже сказал, вы можете читать a === b как «a соответствует b». Вот несколько примеров:
Оператор case основан на методе === :
эквивалентно этому:
Если вы определяете новый класс, экземпляры которого представляют собой какой-то контейнер или диапазон (если у него есть что-то вроде метода include? Или match? ), Вы можете найти полезным переопределить метод === следующим образом:
источник
Исправление обезьян . В Ruby есть открытые классы, поэтому их поведение можно динамически изменять во время выполнения ...
Объекты могут реагировать на неопределенные методы , если
method_missing
иsend
были отменены. При этом используется вызов метода Ruby на основе сообщений. Rails ' ActiveRecord система использует это с большим эффектом.источник
Следующий код меня удивил. Я считаю, что это опасная ошибка: и легко столкнуться, и трудно отладить.
Это печатает:
Но если я просто добавлю
comment =
что-нибудь перед блоком ...Тогда я получаю:
Обычно, когда переменная определяется только внутри блока, она уничтожается в конце блока, а затем сбрасывается
nil
на каждую итерацию. Обычно это то, чего вы ожидаете. Но если переменная будет определена перед блоком, то внешняя переменная используется внутри блока, и его значение , следовательно , сохраняются между итераций.Одним из решений было бы написать вместо этого:
Я думаю, что многие люди (включая меня) склонны писать «
a = b if c
» вместо «a = (c ? b : nil)
», потому что это более читабельно, но, очевидно, у него есть побочные эффекты.источник
a = (b if c)
чтобы получить желаемый эффект, без троичности. Это потому, чтоb if c
еслиc
ложно, то значение равно нулю.При вызове
super
без аргументов замещенный метод фактически вызывается с теми же аргументами, что и замещающий метод.Чтобы действительно позвонить
super
без аргументов, вам нужно сказатьsuper()
.источник
B#hello
естьname = 42
до тогоsuper
, то он говорит «привет 42».По умолчанию блоки и методы возвращают значение последней строки. Добавление
puts
операторов в конец в целях отладки может вызвать неприятные побочные эффекты.источник
Наследование не играет роли в определении видимости метода в Ruby.
источник
У меня было много проблем с пониманием переменных класса, атрибутов класса и методов класса. Этот код может помочь новичку:
источник
я научился осторожно использовать оператор || =. и будьте особенно осторожны, если имеете дело с логическими значениями. Я обычно использовал a || = b как уловку, чтобы дать 'a' значение по умолчанию, если все остальное не удалось, а 'a' оставалось равным нулю. но если a ложно, а b истинно, тогда a будет присвоено значение true.
источник
a = b if a.nil?
или@a = b unless defined?(@a)
.Блоки действительно важно понимать, они используются везде.
Вам не нужны скобки вокруг параметров метода. Используете вы их или нет - решать вам. Некоторые говорят, что вы всегда должны их использовать .
Для обработки исключений используйте подъём и спасение, а не метод throw и catch.
Вы можете использовать,
;
но не обязаны, если не хотите поместить несколько вещей в одну строку.источник
У меня была проблема с Mixins , которые содержат методы экземпляра и методы класса. Этот код может помочь новичку:
Сначала я думал, что могу иметь модули как с методами экземпляра, так и с методами класса, просто сделав следующее:
К сожалению, метод number_of_displays никогда не будет включен или расширен, потому что это «метод класса модуля». Только «методы экземпляра модуля» могут быть включены в класс (как методы экземпляра) или расширены в класс (как методы класса). Вот почему вам нужно поместить методы экземпляра вашего миксина в модуль, а методы класса вашего миксина - в другой модуль (вы обычно помещаете методы класса в подмодуль «ClassMethods»). Благодаря включенному магическому методу вы можете упростить включение как методов экземпляра, так и методов класса всего в один простой вызов «include Displayable» (как показано в примере выше).
Этот миксин будет считать каждое отображение для каждого класса . Счетчик является атрибутом класса, поэтому у каждого класса будет свой собственный (ваша программа, вероятно, выйдет из строя, если вы получите новый класс из класса Person, поскольку счетчик @number_of_displays для производного класса никогда не будет инициализирован). Вы можете заменить @number_of_displays на @@ number_of_displays, чтобы сделать его глобальным счетчиком. В этом случае у каждой иерархии классов будет свой счетчик. Если вам нужен глобальный и уникальный счетчик, вам, вероятно, следует сделать его атрибутом модуля.
Все это было определенно не интуитивно для меня, когда я начинал с Ruby.
Я до сих пор не могу понять, как чисто сделать некоторые из этих методов миксина частными или защищенными (только метод display и number_of_displays должны быть включены как общедоступные методы).
источник
Обратите внимание на обозначение Range.
(По крайней мере, уделите больше внимания, чем я изначально!)
Есть разница между
0..10
(две точки) и0...10
(три точки).Мне очень нравится Руби. Но эта штука точка-точка против точки-точки-точки меня беспокоит. Я думаю, что такая тонкая "особенность" двойного синтаксиса:
не должны приводить к серьезным ошибкам в моих программах.
источник
for (i=0; i<max; i++)
иfor (i=0; i<=max; i++)
Я думаю, что «
and
» и «or
» - это отсылки к Perl, который является одним из наиболее очевидных «родителей» Ruby (самым известным из которых является Smalltalk). Они оба имеют гораздо более низкий приоритет (ниже чем уступки, на самом деле, что , когда поведение отмечено происходит от) , чем&&
и||
которые операторов вы должны использовать.Другие вещи, о которых следует знать, не сразу очевидны:
На самом деле вы не вызываете методы / функции, хотя это вроде как выглядит. Вместо этого, как в Smalltalk, вы отправляете сообщение объекту. Так
method_missing
действительно больше нравитсяmessage_not_understood
.эквивалентно
Символы очень широко используются. Это те вещи, которые начинаются с,
:
и они не сразу очевидны (ну, они не были для меня), но чем раньше вы с ними разберетесь, тем лучше.Ruby хорошо разбирается в «утином типе», следуя принципу, что «если он ходит, как утка, и крякает, как утка ...», что позволяет неформальную замену объектов общим подмножеством методов без какого-либо явного наследования или взаимосвязи примешивания.
источник
Если вы объявляете сеттер (он же мутатор) с помощью
attr_writer
orattr_accessor
(илиdef foo=
), будьте осторожны, вызывая его изнутри класса. Поскольку переменные объявляются неявно, интерпретатор всегда должен разрешатьfoo = bar
как объявление новой переменной с именем foo, а не вызывать методself.foo=(bar)
.Это также относится к объектам Rails ActiveRecord, для которых средства доступа определяются на основе полей в базе данных. Поскольку это даже не переменные экземпляра @-стиля, правильный способ установить эти значения индивидуально с помощью
self.value = 123
илиself['value'] = 123
.источник
Понимание разницы между классом времени и даты. Оба они разные и создают проблемы при использовании их в рельсах. Класс Time иногда конфликтует с другими библиотеками классов Time, присутствующими в стандартной библиотеке ruby / rails. Лично мне потребовалось много времени, чтобы понять, что именно происходит в моем приложении rails. Позже я подумал, когда сделал
Time.new
Речь шла о какой-то библиотеке в месте, о котором я даже не знал.
Извините, если я не совсем понимаю, что хочу сказать. Если другие сталкивались с подобными проблемами, пожалуйста, объясните еще раз.
источник
В прошлом меня зацепило то, что
\n
escape-последовательность символа новой строки ( ), среди прочего, не поддерживается строками в одинарных кавычках. Сама обратная косая черта экранируется. Вы должны использовать двойные кавычки, чтобы экранирование работало должным образом.источник
0 и '' верны, как вы отметили.
У вас может быть метод и модуль / класс с одним и тем же именем (что имеет смысл, потому что метод фактически добавляется к Object и, следовательно, имеет собственное пространство имен).
Множественного наследования не существует, но часто используются «миксин-модули» для добавления общих методов к нескольким классам.
источник
false
иnil
являются ложными. Все остальные - истинные ценности.Методы можно переопределить, и они могут стать скетчем, пока вы не обнаружите причину. ( Следует признать, что эту ошибку, вероятно, немного «сложнее» обнаружить, когда действие контроллера Ruby on Rails переопределяется по ошибке! )
Бегать:
Но вызовите его с включенными предупреждениями, и вы увидите причину:
источник
Я думаю, что всегда полезно использовать .length для вещей ... поскольку размер поддерживается почти всем, а Ruby имеет динамические типы, вы можете получить действительно странные результаты, вызывая .size, когда у вас неправильный тип ... Я бы предпочел получить a NoMethodError: undefined метод `length ', поэтому я обычно никогда не вызываю size для объектов в Ruby.
укусил меня не раз.
Также помните, что у объектов есть идентификаторы, поэтому я стараюсь не использовать переменные call id или object_id, чтобы избежать путаницы. Если мне нужен идентификатор объекта Users, лучше всего назвать его как-то вроде user_id.
Только мои два цента
источник
Я новичок в Ruby, и в моем первом раунде я столкнулся с проблемой, касающейся изменения чисел с плавающей запятой / строк на целое число. Я начал с поплавков и закодировал все как f.to_int . Но когда я продолжил и применил тот же метод для строк, у меня возникла кривая, когда дело дошло до запуска программы.
По сути, у строки нет метода to_int , но есть числа с плавающей точкой и целые числа.
Произвольные скобки меня поначалу тоже подбросили. Я видел какой-то код с и без. Мне потребовалось некоторое время, чтобы понять, что оба стиля приемлемы.
источник
Связанные с ответом monkut,
to_foo
методы Ruby намекают, насколько строго они будут выполнять преобразование.Короткие, например
to_i
,to_s
скажите ему, чтобы он был ленив, и преобразовать их в целевой тип, даже если они не могут быть точно представлены в этом формате. Например:Более длинные явные функции, такие как
to_int
,to_s
означают, что объект может быть изначально представлен как этот тип данных. Например,Rational
класс представляет все рациональные числа, поэтому его можно напрямую представить как целое число Fixnum (или Bignum) путем вызоваto_int
.Если вы не можете вызвать более длинный метод, это означает, что объект не может быть изначально представлен в этом типе.
Итак, в основном, при преобразовании, если вы ленивы с именами методов, Ruby будет ленив с преобразованием.
источник
Из Ruby, почему не
foo = true unless defined?(foo)
выполняет задание?Потому
foo
что определяется какnil
когдаdefined?(foo)
называется.источник
Итерация по рубиновым хешам не гарантируется в каком-либо конкретном порядке. (Это не ошибка, это особенность)
Hash#sort
пригодится, если вам нужен конкретный заказ.Связанный вопрос: почему массив Ruby из 1000 пар ключей и значений хешей всегда находится в определенном порядке?
источник
Однажды меня это рассердило:
источник
1/2
вычисляется значение0
, которое не равно0.5
, независимо от типа. ОднакоRational(1, 2) == 0.5
, и1.0 == 1
.не работает. Вы должны заключить диапазон в круглые скобки, например
так что он не думает, что ты звонишь
5.each
. Я думаю, что это проблема приоритета, как иx = true and false
ошибка.источник