Често је потребно направити копију документа вредност у Руби-у. Иако се ово може чинити једноставним, а то је за једноставне објекте, чим морате направити копију података структура са вишеструким низом или хешевима на истом објекту, брзо ћете пронаћи да их има много замке.
Објекти и референце
Да бисмо разумели шта се догађа, погледајмо неки једноставан код. Прво, оператер додјеле користећи тип ПОД (Обични стари подаци) Руби.
а = 1
б = а
а + = 1
ставља б
Овде оператер додјеле прави копију вриједности а и доделити је б помоћу оператора додјеле. Све промене у а неће се одразити у б. Али шта је са нечим сложенијим? Размотрити ово.
а = [1,2]
б = а
а << 3
ставља б.инспецт
Пре него што покренете горњи програм, покушајте да погодите шта ће бити излаз и зашто. Ово није исто као у претходном примеру, промене у а огледају се у б, али зашто? То је зато што Арраи објект није ПОД тип. Оператор додјеле не прави копију вриједности, већ једноставно копира референца до објекта Арраи. Тхе а и б променљиве су сада референце истом објекту Арраи, све промјене у било којој варијабли ће се видјети у другој.
А сада можете видети зашто копирање не-тривијалних објеката с референцама на друге објекте може бити тешко. Ако једноставно направите копију објекта, ви само копирате референце на дубље објекте, па се ваша копија назива „плитком копијом“.
Шта Руби пружа: дуп и клон
Руби пружа две методе за прављење копија предмета, укључујући и ону за коју се могу направити дубоке копије. Тхе Објект # дуп метода ће направити плитку копију објекта. Да бисте то постигли, дуп метода ће позвати Инитиализе_цопи метода те класе. Шта се тачно ради зависи од класе. У неким класама, као што је Арраи, иницијализираће нови низ са истим члановима као и изворни низ. Ово, међутим, није дубока копија. Узмите у обзир следеће.
а = [1,2]
б = а.дуп
а << 3
ставља б.инспецт
а = [[1,2]]
б = а.дуп
а [0] << 3
ставља б.инспецт
Шта се овде догодило? Тхе Низ # Инитиализе_цопи метода ће заиста направити копију матрице, али та копија је сама по себи плитка копија. Ако имате неке друге типове који нису ПОД у вашем пољу, користећи дуп биће само делимично дубока копија. Биће само дубок као први низ, било који дубљи низови, хеше или ће се други предмети копирати само плитко.
Постоји још једна метода вредна спомена, клон. Метода клона ради исту ствар као дуп са једном важном разликом: очекује се да ће објекти надвладати ову методу оном која може радити дубоке копије.
Па у пракси шта то значи? То значи да свака од ваших класа може дефинирати методу клонирања која ће направити дубоку копију тог објекта. То такође значи да морате написати методу клонирања за сваку класу коју сачињавате.
Трик: Маршал
"Марсхаллинг" објекта је други начин казивања "сериализатион" објекта. Другим речима, претворите тај објект у ток знакова који се може записати у датотеку коју касније можете „демарширати“ или „несериализовати“ да бисте добили исти објект. Ово се може искористити за добијање дубоке копије било којег предмета.
а = [[1,2]]
б = маршал.лоад (Марсхал.думп (а))
а [0] << 3
ставља б.инспецт
Шта се овде догодило? Марсхал.думп ствара "думп" угнијежђене матрице спремљене у а. Овај думп је бинарни низ знакова који треба да се похрани у датотеку. У њему се налази цео садржај низа, потпуна дубока копија. Следећи, Марсхал.лоад чини супротно. Анализира овај низ бинарних знакова и ствара потпуно нови Арраи, са потпуно новим елементима Арраи-а.
Али ово је трик. Неефикасан је, неће радити на свим објектима (шта се деси ако покушате клонирати мрежну везу на овај начин?) И вероватно није ужасно брз. Међутим, то је најлакши начин да дубоке копије немају прилагођене Инитиализе_цопи или клон методе. Такође, иста ствар се може учинити са методама попут то_иамл или то_кмл ако имате учитане библиотеке које их подржавају.