Оба определения эквивалентны. Обычно вы будете использовать форму fun(n::Integer)
и применять fun(n::T) where T<:Integer
только в том случае, если вам нужно использовать конкретный тип T
непосредственно в коде. Например, рассмотрим следующие определения из базы (все следующие определения также из базы), где он имеет естественное использование:
zero(::Type{T}) where {T<:Number} = convert(T,0)
или
(+)(x::T, y::T) where {T<:BitInteger} = add_int(x, y)
И даже если вам во многих случаях требуется информация о типе, достаточно использовать функцию typeof
. Опять пример определения:
oftype(x, y) = convert(typeof(x), y)
Даже если вы используете параметрический тип, вы часто можете избегать использования предложения where
(немного подробного), например:
median(r::AbstractRange{<:Real}) = mean(r)
потому что вас не волнует фактическое значение параметра в теле функции.
Теперь - если вы пользователь Юлии, как я, - вопрос в том, как убедить себя, что это работает, как и ожидалось. Существуют следующие методы:
- вы можете проверить, что одно определение перезаписывает другое в таблице методов (т. Е. После оценки обоих определений для этой функции присутствует только один метод);
- вы можете проверить код, сгенерированный обеими функциями, используя
@code_typed
, @code_warntype
, @code_llvm
или @code_native
и т. Д. И выяснить, что это один и тот же
- наконец, вы можете сравнить код производительности с помощью
BenchmarkTools
Хороший сюжет, объясняющий, что Джулия делает с вашим кодом, находится здесь http://slides.com/valentinchuravy/julia-parallelism#/1/1 (я также рекомендую всю презентацию любому пользователю Джулии - это отлично). И вы можете видеть на нем, что Джулия после понижения AST применяет шаг вывода типа, чтобы специализировать вызов функции перед шагом кодирования LLVM.
Вы можете намекнуть компилятору Julia, чтобы избежать специализации. Это делается с помощью макроса @nospecialize
на Julia 0.7 (хотя это только подсказка).