2014-02-14 2 views
2

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

class Foo 
    def Bar(str) 
    year = str[0..1].to_i + 2000 
    month = str[2].ord - 48 
    day = str[3].ord - 48 
    hour = str[4].ord - 48 
    min = str[5].ord - 48 
    sec = str[6].ord - 48 

    # ... 
    end 
end 

[Если вам интересно, о необходимости использования ord здесь, а не to_i, вы хотели бы видеть this other question для больше контекста.]

Я хотел бы устранить 48 магическое число здесь. Единственным местом, где будет использоваться это магическое число, является этот конкретный метод. Я не могу объявить его как константу внутри метода:

class Foo 
    def Bar 
    ADJ = 48 
    month = str[2].ord - ADJ 
    day = str[3].ord - ADJ 
    hour = str[4].ord - ADJ 
    min = str[5].ord - ADJ 
    sec = str[6].ord - ADJ 
    # ... 
    end 
end 

потому, что приводит к ошибке dynamic constant assignment (SyntaxError). Поскольку ADJ применим только к этому методу, для меня не имеет большого значения сделать его переменной класса.

Эта функция будет вызываться часто; Я бы хотел, чтобы решение, по крайней мере, не было медленным.

В C++ я мог бы сделать это static const unsigned внутри метода или переместить его в неназванный namespace.

Что такое рубинистский способ устранить это магическое число?

+0

Путь Rubyist не использовать 'ord', а использовать' to_i' и не использовать методы, начинающиеся с капитала. – sawa

+0

@sawa: Потому что мне нужен код ASCII этого символа. Например, если 'str [2]' содержит букву '=', мне нужно получить '61'. Вызов 'to_i' вернет' 0'. Я делаю это неправильно? –

+0

Возможно, вы сможете сделать это таким образом, но если вы заботитесь о том, чтобы сделать это, Ruby-way, использование 'ord', определенно, не способ пойти в первую очередь. Ваш код зависит от кодировки. Это очень плохая практика. – sawa

ответ

2

Моя рекомендация будет просто использовать переменную.

adj = 48 

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

+0

Будет ли эта переменная создаваться при каждом вызове метода? Разве это противоречило бы этому решению «не замедлялось»? –

+2

@JohnDibling: возможно, но я думаю, что проблема с производительностью относится к категории «микро-оптимизации». Для этого (или любого приложения), вероятно, больше проблем с производительностью, чем создание переменной. – maerics

+0

К счастью, '48' - неизменный объект, поэтому он не создается каждый раз. Переменная, указывающая на нее, будет воссоздаваться каждый раз, но это сопоставимо с увеличением индекса 'i' в цикле. – sawa

2

Вы должны перенести эту константу в определение класса/модуля.

Это лучше, чтобы переместить метод модуля и добавить константу там:

module Foo 
    XYZ = ... 

    def bar 
     ... 
    end 
end 
+0

Даже если это не относится ко всему классу? Для меня это кажется плохим дизайном, но я могу застрять в умении C++. –

+1

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

+0

Но мне кажется, что * метод * ** делает ** вписывается в класс. –

Смежные вопросы