Комментарии 66
Спасибо за оперативность статей, ненавижу ждать следующих глав/частей/и т.д.
Желаю не потерять боевой заряд, и писать больше/лучше/чаще, ибо полезно, познавательно, и читаем =)
Желаю не потерять боевой заряд, и писать больше/лучше/чаще, ибо полезно, познавательно, и читаем =)
class Dog
def set_name( aName )
@myname = aName
end
def get_name
return @myname
end
def gav
return 'r-r-r-r!'
end
end
dog1 = Dog.new
puts(dog1.get_name)
puts(dog1.gav)
выводит:
nil
r-r-r-r!
То есть одна из самых трудноотлавливаемых ошибок (неиницализированная переменная) в Ruby вообще за ошибку, или хотя бы достойной предупреждения, не считается?
Странно, что даже не получил никаких предупреждений, просто
Ой, а я уже исправлять ринулся :))) Да, на самом деле просто nil
Выполнил пример, получил предупреждение в IDE (Netbeas).
А вы в консоли выполняли? Версия руби 1.8?
А вы в консоли выполняли? Версия руби 1.8?
>Возможность иметь несколько классов, содержащих одноименные методы, называется полиморфизм.
Вообще понятие полиморфизма намного шире, главное в нем, по-моему, что возможны следующая операция (псевдокод. как на Ryby написать, вроде еще «не проходили» массивы и итераторы по ним
pets = [new Dog, new Cat]
foreach pets as pet
{
print pet.get_name
}
Вообще понятие полиморфизма намного шире, главное в нем, по-моему, что возможны следующая операция (псевдокод. как на Ryby написать, вроде еще «не проходили» массивы и итераторы по ним
pets = [new Dog, new Cat]
foreach pets as pet
{
print pet.get_name
}
>как на Ryby написать
pets = [Dog.new, Cat.new]
pets.each {|pet| puts pet.name}
вот так ;)
pets = [Dog.new, Cat.new]
pets.each {|pet| puts pet.name}
вот так ;)
Я как Java программист могу сказать вам по этому поводу, что это называется рефлексией) По крайней мере в Java. Полиморфизм поидее это:
Полиморфи́зм (в языках программирования) — взаимозаменяемость объектов с одинаковым интерфейсом. (с) Википедия. Так же полиморфизм возможет если объекты предки расриряют общий суперкласс.
Хотя в динамических языках программирования вполне может быть и по другому)
Полиморфи́зм (в языках программирования) — взаимозаменяемость объектов с одинаковым интерфейсом. (с) Википедия. Так же полиморфизм возможет если объекты предки расриряют общий суперкласс.
Хотя в динамических языках программирования вполне может быть и по другому)
ИМХО, транслит в названиях переменных, функции, метода, класса — дурная привычка.
moya = Dog.new
tvoya = Dog.new
коробит знающих англ. язык и ничего не означает для не владеющих им.
moya.skazi-gav-gromko — нехорошо, имхо.
moya = Dog.new
tvoya = Dog.new
коробит знающих англ. язык и ничего не означает для не владеющих им.
moya.skazi-gav-gromko — нехорошо, имхо.
OK, будем писать по-английски
:) да я так, побурчал. Однако, спасибо за обратную связь, с вниманием читаю ваши статьи. Пример с собакой не из открытой книжки (ruby open book) по руби?
Эта собака с переменными из The Book of Ruby — во многих книгах ООП показывают на животных и собаках в частности :)
зря вы просто побурчали, писать транслитом идентификаторы в коде это просто невообразимый пипец.
Вот жутчайший пример:
ru.wikibooks.org/wiki/Введение_в_язык_Scheme_для_школьников
Вот жутчайший пример:
ru.wikibooks.org/wiki/Введение_в_язык_Scheme_для_школьников
спасибо за очередную статью)
с нетерпением жду следующую каплю.
с нетерпением жду следующую каплю.
Отлично, слежу за всеми выпусками, так как параллельно уже почти прочел книжечку по Руби, всё четко и очень доступно, продолжайте. Была бы сила, плюсанул…
Шустрый ты парнишка. Я слаживаю твои капли в стакан ;)
ИМХО логичнее было бы использовать конструктор
class Dog
def initialize(dogName)
@name = dogName
end
def name
puts @name
end
end
тогда можно написать
rex = Dog.new(«rex»)
rex.name
class Dog
def initialize(dogName)
@name = dogName
end
def name
puts @name
end
end
тогда можно написать
rex = Dog.new(«rex»)
rex.name
За конструктор обеими руками «за», особенно раз руби по дефолту позволяет не инициализировать переменные, но вот переменные с присваиванием только в конструкторе как-то не тру, имхо. Больше на константы похожи, чем на переменные :)
само собой. просто я не стал весь класс переписывать полностью, а только показал пример на использование конструктора.
вот более полная версия
class Dog
def initialize(dogName)
@name = dogName
end
def getName
puts @name
end
attr_accessor :name
end
rex = Dog.new(«rex»)
rex.getName
>>rex
rex.name = «milo»
puts rex.name
>>milo
вот более полная версия
class Dog
def initialize(dogName)
@name = dogName
end
def getName
puts @name
end
attr_accessor :name
end
rex = Dog.new(«rex»)
rex.getName
>>rex
rex.name = «milo»
puts rex.name
>>milo
Просто думаю многие ничего не знают о руби, кроме того, что написано в «каплях», и не зная, что, например, можно создавать методы вида name= и про аксессоры типа ридеров и райтеров (о чем я узнал из коментов :) ) первый ваш код выглядит каким-то ущербным :) в том смысле, что кажется, что отказавшись от attr_accesor мы теряем возможность писать rex.name = 'rex' и будем вынуждены пользоваться rex.set_name('rex');
> def getName
лишний метод-алиас, поскольку attr_accessor :name создаст геттер (ридер) для @name;
Вообще, свои геттеры (ридеры) и сеттеры (райтеры) лучше описывать, когда установка/чтение проперти более сложное, нежели простое «верни прямое значение», «установи прямое значение». Для примитивных же reader'ов и writter'ов (и для их обобщающих accessor'ов) достаточно соответствующих классовых методов.
def a
#какие-то сложные вычисления возвращающие некоторое значение, а не просто «примитивный „return“
end
def a=
#тоже могут быть сложные вычисление перед установкой проверти, а не просто „примитивный =“
end
attr_reader :b # только для чтения (будет создан метод def b @b end)
attr_writer :c # только для записи (будет создан метод def c=(val) @c = val end)
attr_accessor :d # объединение двух предыдущих „примитивных ридера и райтера“
лишний метод-алиас, поскольку attr_accessor :name создаст геттер (ридер) для @name;
Вообще, свои геттеры (ридеры) и сеттеры (райтеры) лучше описывать, когда установка/чтение проперти более сложное, нежели простое «верни прямое значение», «установи прямое значение». Для примитивных же reader'ов и writter'ов (и для их обобщающих accessor'ов) достаточно соответствующих классовых методов.
def a
#какие-то сложные вычисления возвращающие некоторое значение, а не просто «примитивный „return“
end
def a=
#тоже могут быть сложные вычисление перед установкой проверти, а не просто „примитивный =“
end
attr_reader :b # только для чтения (будет создан метод def b @b end)
attr_writer :c # только для записи (будет создан метод def c=(val) @c = val end)
attr_accessor :d # объединение двух предыдущих „примитивных ридера и райтера“
def initialize(dogName) — экто конструтор класса получается?
конструктор здесь — метод initialize. он вызывается когда мы создаем новый экземпляр класса (Dog.new). Конструктор может быть без параметров, а может с параметрами, как в данном случае. можно определять несколько конструкторов, напр. с параметрами и без, с разным числом параметров и пр.
class Dog
def initialize #без параметров
@name = «rex» #по умолчанию собаку зовут Рекс
end
def initialize(dogName) #но если нам не нравится
@name = dogName #мы можем назвать ее и по-другому
end
<...>
end
class Dog
def initialize #без параметров
@name = «rex» #по умолчанию собаку зовут Рекс
end
def initialize(dogName) #но если нам не нравится
@name = dogName #мы можем назвать ее и по-другому
end
<...>
end
Еще пример полиморфизма :)
А вопрос такой есть: как определяется конструктор — по имени initialize или по тому, что он первый описан, или я еще чего-то не доглядел?
А вопрос такой есть: как определяется конструктор — по имени initialize или по тому, что он первый описан, или я еще чего-то не доглядел?
> можно определять несколько конструкторов, напр. с параметрами и без, с разным числом параметров и пр.
Это что-то из мира С++ и Java. В Ruby второй метод initialize просто-напросто перезапишет первый initialize. В итоге, без параметров Вы не вызовите метод. А параметры по умолчанию можно в самом initialize передавать:
Можно и так:
Это что-то из мира С++ и Java. В Ruby второй метод initialize просто-напросто перезапишет первый initialize. В итоге, без параметров Вы не вызовите метод. А параметры по умолчанию можно в самом initialize передавать:
class A def initialize(a=10) @a = a end end a = A.new # @a = 10 b = A.new(20) # @a = 20
Можно и так:
def initialize(a=nil) @a = a || 10 end
хм, действительно… прошу прощения, попутал что-то
нда. Только начинает нравиться, как что-нибудь всплывает. То ++ нет, то конструктор только один
Отсутствие оверлоадинга методов — это ограничение динамических языков.
Хотите два конструктора — используйте переменное число параметров.
Такой же код для перегрузки методов.
Хотите два конструктора — используйте переменное число параметров.
class Test def initialize *args if args.size == 1 puts "first constructor" elsif args.size == 2 puts "second constructor" else raise "Required 1 or 2 parameters" end end end Test.new("asdf") #=> first constructor" Test.new("asdf","asdf") #=> "second constructor" Test.new() #=> `initialize': Required 1 or 2 parameters (RuntimeError)
Такой же код для перегрузки методов.
Я понимаю — выкрутиться можно. Это хорошо.
Но вот смотрите например в C#.
При компиляции в месте создания объекта SimpleParser будет сразу сгенерирован вызов того конструктора, который нужен в зависимости от переданного (или не переданного вовсе) параметра. И в рантайме уже анализировать ничего не нужно. А это скорость
Но вот смотрите например в C#.
class SimpleParser
{
public SimpleParser()
{
}
public SimpleParser(String fileName)
{
}
public SimpleParser(Stream stream)
{
}
public SimpleParser(BinaryReader reader)
{
}
}
* This source code was highlighted with Source Code Highlighter.
При компиляции в месте создания объекта SimpleParser будет сразу сгенерирован вызов того конструктора, который нужен в зависимости от переданного (или не переданного вовсе) параметра. И в рантайме уже анализировать ничего не нужно. А это скорость
> А это скорость
А статические системы в любом случае быстрее динамических. С другой стороны, статические не обладают такой гибкостью, как динамические.
А статические системы в любом случае быстрее динамических. С другой стороны, статические не обладают такой гибкостью, как динамические.
Руби, вроде как, язык интерпретируемый и по любому анализ в рантайме будет проходить, насколько я понимаю, что такое интерпретатор
Я просто надеюсь, что он предварительно какой-нибудь байт-код генерит.
В таком случае, будь в нем overload, проверка параметров проводилась бы один раз на этапе генерации байт-кода, а так при каждом создании объекта
В таком случае, будь в нем overload, проверка параметров проводилась бы один раз на этапе генерации байт-кода, а так при каждом создании объекта
Во-первых, в ветке Ruby 1.8 компилляции в байткод нет, только в 1.9.
Во-вторых, не в компиляции дело.
Ruby — это динамический язык, в динамических языках нет оверлоадинга.
И по скорости динамические языки всегда медленнее статических.
Если для ваших задач критична скорость — используйте тот же C#:)
Во-вторых, не в компиляции дело.
Ruby — это динамический язык, в динамических языках нет оверлоадинга.
И по скорости динамические языки всегда медленнее статических.
Если для ваших задач критична скорость — используйте тот же C#:)
Если более точно, что initialize — это инциализатор порожденного объекта (инстанса). Конструктор, именно в плане конструирования — это new (и то, new — это лишь оболочка для allocate (выделяет память) и initialize (инициализирует объект)).
НЛО прилетело и опубликовало эту надпись здесь
Вот, спасибо! А только хотел спросить, как реализуется внутренне конструкции a.name и a.name=при использовании attr_acсesor (вернее последняя, с первой-то все понятно), можно ли как-то изменить поведение, например валидацию провести в «сеттере» или же attr_acсesor является аналогом public переменных класса в других языках и способа контроля (простого) в присваивании не существует. А так сразу все понятно стало :)
Да, поскольку, инстанс-переменные являются настоящими пропертями, то, лучше бы, показать, что get_name и set_name — это прерогатива того, что работает не с виртуальными пропертями. В Руби же для таких целей есть полноценные аксессроры (ридеры, райтеры): name и name= (который, как было сказано выше, создаются автоматом в «примитивном виде» (установить простое значение / вернуть простое значение) классовыми методами attr_accessor, attr_reader и attr_writer)
Благодарю! Я тоже весь в сомнениях был, а в книгах никаких подробностей :(
есть еще, по аналогии с attr_accessor:
attr_reader
attr_writer
attr_reader
attr_writer
И всё таки мне кажется что руби не такой православный как питон.
По рубишному соглашению, мультивордовые имена необходимо писать через underscore. @myname и особенно aName выбивают из колеи, делают код нечитаемым. Надо так: a_name, @my_name. Через капиталайзед, пишутся мультивордовые имена классов(e.g. MyClassName).
и вообще:
и вообще:
Table 2.1. Example variable and class names ----------------------------------------------------------+--------------- Variables | Constants and | Class Names ----------------------------------------------------------+--------------- Local | Global | Instance | Class | ----------------+--------------+--------------+-----------| name | $debug | @name | @@total | PI fish_and_chips | $CUSTOMER | @point_1 | @@symtab | FeetPerMile x_axis | $_ | @X | @@N | String thx1138 | $plan9 | @_ | @@x_pos | MyClass _26 | $Global | @plan9 | @@SINGLE | JazzSong --------------------------------------------------------------------------
Змейка в качестве питомца (pet), это сильно :)
Тем не менее, спасибо за статьи. Сам брался как-то за руби, но толи книги не те попались, то ли голова тогда не соображала, мне он показался какой-то излишне мудрёный. А тут смотрю — вполне себе красиво, мне нравится :)
Тем не менее, спасибо за статьи. Сам брался как-то за руби, но толи книги не те попались, то ли голова тогда не соображала, мне он показался какой-то излишне мудрёный. А тут смотрю — вполне себе красиво, мне нравится :)
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Покорим Ruby вместе! Капля четвертая