Создайте несколько методов автоматически - PullRequest
4 голосов
/ 12 апреля 2020

Я могу определить function, который обрабатывает Integer с:

function twice(a::Int64) a + a end

Эта функция не может обрабатывать Float с. Если я хочу этого, мне нужно определить другой метод:

function twice(a::Float64) a + a end

Но подождите, это выглядит точно так же, кроме определения типа. Итак, когда я сплю ночью, есть возможность создать такие определения методов (все идентично, кроме типа / комбинации типов) с помощью ... макроса, может быть? Что-то вроде

@create_all_methods ("twice(a::$type ) a + a end", ["Int64", "Float64"])
  1. Возможно ли это и если да, то как?

  2. Может ли вопрос вообще не иметь никакого смысла, потому что разве нет ситуации, когда function twice(a) a + a end не достиг бы того же самого результата?

Спасибо за вашу помощь заранее.

Ответы [ 2 ]

7 голосов
/ 12 апреля 2020

Есть несколько способов достичь этого. Проще всего было бы просто пропустить тип a T, тогда ваш метод выглядел бы так:

function twice(a) a + a end

Это эквивалентно

function twice(a::Any) a + a end

Но, возможно, вы не хотите чтобы определить это для всех типов, или у вас уже есть другое определение для twice(a::Any), так что вы можете ограничить свое определение общим супертипом Int64 и Float64. Этот общий супертип можно найти с помощью typejoin(Float64, Int64) и даст результат Real, поэтому ваше определение теперь будет

function twice(a::Real) a + a end

. Это также создает метод для других подтипов Real, таких как a::Int32 , так что если вы действительно хотите метод только для Int64 и Float64, вы можете создать тип объединения. Тогда метод будет выглядеть следующим образом:

    function twice(a::Union{Int64, Float64}) a + a end

Наконец, действительно возможно достичь того, чего вы хотели достичь с помощью макроса. В этом случае это не имеет смысла, но в более сложных случаях часто используется либо функция eval, либо макрос @eval. Ваш код может выглядеть следующим образом:

for T in (Int64, Float64)
    @eval function twice(a::$T) a + a end
end

Если вы только начали изучать Юлию, я бы не советовал использовать eval, так как с использованием eval связаны некоторые опасности / анти-паттерны. .

6 голосов
/ 12 апреля 2020

Простой способ создания методов для двух или более типов ввода заключается в использовании Union:

twice(a::Union{T1, T2, T3}) = a + a

, где T1, T2, T3 и т. Д. это конкретные типы, такие как Int или Float64.

Чаще всего вы определяете его для некоторого абстрактного супертипа, например

twice(a::Number) = a + a

Но в большинстве случаев, Вы должны просто начать с определения обобщенной c функции

twice(a) = a + a

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

...