Есть ли в Юлии такая концепция, как typedef в C ++? - PullRequest
0 голосов
/ 14 февраля 2019

Я пытаюсь выучить Джулию и начал с переписывания одной из моих программ на С ++.

У меня проблемы с поиском хорошего способа представления следующей концепции в Юлии.

У меня есть несколько структур, все из которых являются своего рода коллекцией.Допустим, у меня есть адресная книга и фотоальбом.Каждая коллекция имеет очень разные элементы.Теперь в C ++ довольно легко создать переменную типа Photo, если я знаю, что PhotoAlbum был передан в функцию.

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

Так я бы сделал это в C ++

class AddressBook
{
  public:
    typedef PersonalDetail Element;
}


class PhotoAlbum
{
  public:
    typedef Photo Element;
}


template<typename Collection>
void printFirstElement<Collection>(const Collection& c)
{
  const typename Collection::Element firstElement = //c.first();...
  // do something with firstElement
}

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

Поскольку переменные в Julia могут содержать типы, вы можете просто сделать

struct PersonalDetail
end
struct Photo
end

struct AddressBook
    Element
    AddressBook(Element=PersonalDetail) = new(Element)
end

struct PhotoAlbum
    Element
    PhotoAlbum(Element=Photo) = new(Element)
end

PhotoAlbum()

При этом вы можете писать функции без указания их типов

function printFirstElement(c)
    @show c[1]
end
printFirstElement([AddressBook()])
printFirstElement([PhotoAlbum()])
printFirstElement([rand([AddressBook() PhotoAlbum()])])
printFirstElement(1:5) # doesn't specify element type with `Element`, but we can still access its first element
0 голосов
/ 14 февраля 2019

Если я правильно понимаю вашу проблему, я бы сказал, что вам не нужно об этом думать, потому что компилятор будет знать требуемые типы.Например, в приведенном выше коде, когда вы вызываете first(c) (это будет эквивалент c.first()), тип этой переменной будет известен во время компиляции (вы можете подтвердить это, запустив @code_warntype в вашей функции).

Если бы вы предоставили полный небольшой рабочий пример, я мог бы дать вам рабочий код для этого.

Более сложная тема - присоединение метаданных к вашим типам.Есть несколько способов сделать это.Позвольте мне показать вам один из них - через параметрический абстрактный тип.

abstract type AbstractCollection{T} end
struct PersonalDetail end
struct AddressBook <: AbstractCollection{PersonalDetail} end
struct Photo end
struct PhotoAlbum <: AbstractCollection{Photo} end
getcollectiontype(::AbstractCollection{T}) where T = T

и теперь вы можете написать что-то вроде этого, чтобы извлечь метаданные

julia> ab = AddressBook()
AddressBook()

julia> pa = PhotoAlbum()
PhotoAlbum()

julia> getcollectiontype(ab)
PersonalDetail

julia> getcollectiontype(pa)
Photo

Конечно, это MWE, и я не уверен, нужно ли вам это в вашем коде (если вы показываете небольшой полный рабочий код, мы можем обсудить лучшую стратегию реализации).

Также что-то подобное может вообще не понадобиться.Например, у вас есть стандартная функция eltype, которая должна возвращать тип элемента в коллекции.Для этой функции вы можете добавить методы для ваших конкретных типов, чтобы получить информацию о типе элемента, который они содержат.Затем вы можете просто запустить eltype(collection) в своем коде и снова - во время компиляции - у вас будет информация о типе элемента коллекции.

Также обратите внимание, что типы в Julia также являются значениями, например, следующимкод просто работает, и компилятор знает все типы по мере необходимости (функция f пытается преобразовать свой второй аргумент y в тип своего первого аргумента x, используя конструктор типов):

julia> f(x,y) = typeof(x)(y)
f (generic function with 1 method)

julia> f(10, 2.0)
2

julia> f(10.0, 2)
2.0

julia> @code_warntype f(10.0, 2)
Body::Float64
1 ─ %1 = (Base.sitofp)(Float64, y)::Float64
└──      return %1

Вышеприведенное определение эквивалентно следующему f(x::T,y) = T(y).

...