Почему эта строка из «Документации языка Julia» определяет внешний конструктор для случая, когда входные параметры имеют разные типы? - PullRequest
4 голосов
/ 20 февраля 2020

Я перечитываю Документацию по языку Julia, представляющую интерес для создания приложения с производственной звуковой очередью, и раздел, касающийся конструкторов c параметров и внешних конструкторов, запутал меня. Пример, который они показывают, выглядит следующим образом:

julia> struct OurRational{T<:Integer} <: Real
           num::T
           den::T
           function OurRational{T}(num::T, den::T) where T<:Integer
               if num == 0 && den == 0
                    error("invalid rational: 0//0")
               end
               g = gcd(den, num)
               num = div(num, g)
               den = div(den, g)
               new(num, den)
           end
       end

julia> OurRational(n::T, d::T) where {T<:Integer} = OurRational{T}(n,d)
OurRational

julia> OurRational(n::Integer, d::Integer) = OurRational(promote(n,d)...)
OurRational

julia> OurRational(n::Integer) = OurRational(n,one(n))
OurRational

В документации говорится:

Первый - это «стандартный» общий (внешний) конструктор, который выводит параметр типа T из тип числителя и знаменателя, когда они имеют одинаковый тип.

Из этого я пришел к выводу, что этот конструктор обрабатывает случай двух параметров. Он выводит T из типа (num и den), а затем передает его внутреннему конструктору OurRational.

В документации говорится:

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

Глядя на код, я не вижу, как это происходит. Исходя из того, как я думаю, что Юлия оценивает, разве второй конструктор не обработает случай, когда оба n и d явные целые числа? Если иначе, у меня возникнут проблемы с тем, как Джулия видит эту линию. Кроме того, эллипсы в суффиксе присваивания означают что-то вроде "now go" для внешнего конструктора, когда оба параметра имеют одинаковый тип ", верно?

Я хорошо понимаю третий внешний конструктор.

1 Ответ

4 голосов
/ 20 февраля 2020

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

Юлия, как вы знаете, имеет много встроенных целочисленных типов. Рассмотрим, например, UInt8, который является типом по умолчанию для однобайтового синтаксиса, например 0x1f. Посмотрите на результаты, когда мы смешиваем UInt8 и тип Integer по умолчанию, Int64:

julia> struct OurRational{T<:Integer} <: Real
           num::T
           den::T
           function OurRational{T}(num::T, den::T) where T<:Integer
               println("Inner")
               if num == 0 && den == 0
                   error("invalid rational: 0//0")
               end
               g = gcd(den, num)
               num = div(num, g)
               den = div(den, g)
               new(num, den)
           end
       end

julia>

julia> OurRational(n::T, d::T) where {T<:Integer} = begin println("Outer 1"); OurRational{T}(n,d) end
OurRational

julia> OurRational(n::Integer, d::Integer) = begin println("Outer 2"); OurRational(promote(n,d)...) end
OurRational

julia> OurRational(n::Integer) = begin println("Outer 3"); OurRational(n,one(n)) end
OurRational

julia> OurRational{UInt8}(0x2, 0x5)
Inner
OurRational{UInt8}(0x02, 0x05)

julia> OurRational(2, 5)
Outer 1
Inner
OurRational{Int64}(2, 5)

julia> OurRational(0x2, 5)
Outer 2
Outer 1
Inner
OurRational{Int64}(2, 5)

julia> OurRational(0x3)
Outer 3
Outer 1
Inner
OurRational{UInt8}(0x03, 0x01)

Итак, второй внешний конструктор переносит аргументы в тот же тип, а затем передает их первому внешнему конструктору, который затем руки прочь к внутреннему конструктору.

...