Ответ на Ваш вопрос:
При определении нового типа в Джулии, он является общим, чтобы расширить некоторые из стандартных методов в Base
к новому типу, в том числе deepcopy
. Например:
type MyType
x::Vector
y::Vector
end
import Base.deepcopy
Base.deepcopy(m::MyType) = MyType(deepcopy(m.x), deepcopy(m.y))
Теперь вы можете вызвать deepcopy
над экземпляром MyType
, и вы получите новый, по-настоящему независимой, копию MyType
как выход.
Примечание: мой import Base.deepcopy
на самом деле избыточен, так как я указал Base
в определении моей функции, например. Base.deepcopy(m::MyType)
. Тем не менее, я сделал оба из них, чтобы показать вам два способа расширения метода от Base
.
Второе примечание, если тип имеет много полей, вы можете вместо перебирать поля, используя deepcopy
следующим образом:
Base.deepcopy(m::MyType) = MyType([ deepcopy(getfield(m, k)) for k = 1:length(names(m)) ]...)
Комментарий на код:
Во-первых, стандартная практика в Julia для использования имени типа, например Component1
вместо component1
. Конечно, вам не обязательно это делать, но ...
Во-вторых, из Julia docs performance tips: Объявлять конкретные типы для полей композитных типов. Обратите внимание, что вы можете параметризовать эти объявления, например.
type Component1{T1, T2}
x::T1
y::T2
end
В-третьих, вот как я бы определил свой новый тип:
type Mixture{T}
components::Vector{T}
Mixture{T}(c::Vector{T}) = new(c)
end
Mixture{T}(c::Vector{T}) = Mixture{eltype(c)}(c)
Mixture(x, K::Int) = Mixture([ deepcopy(x) for k = 1:K ])
Есть несколько важных различий здесь между моим кодом и вашим. Я пройду через них по одному.
Ваше поле K
было излишним (я думаю), потому что оно просто должно быть длиной components
.Так что может быть проще просто распространить метод length
к новому типу следующим образом:
Base.length(m::Mixture) = length(m.components)
и теперь вы можете использовать length(m)
, где m
является экземпляром Mixture
, чтобы получить то, что было ранее сохраненными в K
поле.
Внутренний конструктор в вашем виде mixture
был необычным. Стандартная практика заключается в том, что внутренний конструктор принимает аргументы, которые соответствуют друг другу (последовательно) полям вашего типа, а затем остальная часть внутреннего конструктора просто выполняет любые проверки ошибок, которые вы хотели бы сделать, всякий раз, тип. Вы отклонились от этого, так как qq
не был (обязательно) массивом. Такое поведение лучше зарезервировано для внешних конструкторов. Итак, что я сделал с конструкторами?
Внутренний конструктор Mixture
на самом деле ничего не делает, кроме как передать аргумент в поле через new
. Это связано с тем, что в настоящее время нет никаких проверок ошибок, которые мне нужно выполнить (но я могу легко добавить их в будущем).
Если я хочу назвать этот внутренний конструктор, мне нужно написать что-то вроде m = Mixture{MyType}(x)
, где x
- Vector{MyType}
. Это немного раздражает. Поэтому мой первый внешний конструктор автоматически передает содержимое {...}
с использованием eltype(x)
. Из-за моего первого внешнего конструктора я могу теперь инициализировать Mixture
, используя m = Mixture(x)
вместо m = Mixture{MyType}(x)
Мой второй внешний конструктор соответствует вашему внутреннему конструктору. Мне кажется, что вы после этого должны инициализировать Mixture
с тем же компонентом в каждом поле components
, повторяющийся K
раз. Поэтому я делаю это с пониманием петли над x
, которое будет работать до тех пор, пока метод deepcopy
определен для x
. Если метод deepcopy
не существует, вы получите сообщение об ошибке No Method Exists
. Этот вид программирования называется утиным типом, а в Julia обычно не существует ограничения производительности при его использовании.
Обратите внимание, что мой второй внешний конструктор вызовет мой первый внешний конструктор K
раз, и каждый раз мой первый внешний конструктор вызовет мой внутренний конструктор. Функциональность вложенности таким образом будет в более сложных сценариях массовым сокращением дублирования кода.
Извините, этого много, что я знаю. Надеюсь, поможет.
Благодарим вас за полный ответ. Я был знаком с концепцией множественной диспетчеризации, но я не был уверен, что лучший способ - изменить Base.deepcopy. Также спасибо за комментарии. В отношении третьего комментария и устранения необходимости указывать тип в конструкторе, хотя мне удалось использовать ваш метод, но я не совсем понимаю его! – Adham
@Adham Я обновил свой ответ. Если все еще неясно, дайте мне знать, и я попробую еще раз :-) –
Спасибо. Теперь это намного яснее (для меня как новичок в Джулии: D) – Adham