Solid Bits - съхранение спрямо памет

Кредит за снимки

Кодирането в Solidity не винаги е интуитивно, но е забавно. Едно от малките предизвикателства, с които трябваше да увия главата си, беше разликата между съхранение спрямо памет.

Представете си прост пример като този по-долу

плътност на прагмата ^ 0.4.22;
договор плодове {
    string [] публични елементи;
    constructor () public {
        items.push ( "ябълка");
        items.push ( "оранжево");
    }
}

Ако щях да разгърна този договор, елементите в индекса 0 и 1 биха съответно „ябълка“ и „оранжево“. Достатъчно лесно.

Какво ще стане, ако се опитам да създам нов масив от функцията на конструктора ми, насочен към изменчивия масив от елементи? Изглежда достатъчно лесно.

constructor () public {
  ...
  string [] newItems = елементи;
}

Но почакай! получаваме предупреждение като това по-долу!

Разберете предупреждението? Не бях и аз.

За да разберем напълно какво се случва, нека да обсъдим как Solidity интерпретира паметта спрямо съхранението.

Съхранение срещу памет

Solidity разглежда връзката между съхранението и паметта по 2 различни начина.

  1. Данни за състоянието на договора
  • съхранение: променливи, определени на най-високо ниво вътре в договора. (напр .: артикули)
  • памет: Структури (Вижте http://solidity.readthedocs.io/en/v0.4.21/types.html, ако не знаете какво е структура)

2. Декларация за променлива стойност

  • В този сценарий декларацията за променлива стойност може да бъде дефинирана като памет или памет в зависимост от това как искате да запазите тази променлива (допълнително обяснено по-долу)

За нашата примерна цел артикулите са състояние на съхранение вътре в договора за плодове. С новата променлива newItems имаме две опции, запишете променливата в паметта или съхранението. Ще прегледам и двете опции по-долу.

NewItems като съхранение

Ако newItems беше запазен като съхранение, трябва да включите съхранението на ключови думи преди newItems. Пример, показан по-долу.

string [] storage newItems = елементи;

Като добавите стойността на съхранението, предупреждението трябва да изчезне. Но какво точно прави това? С добавяне на хранилище, newItems сега POINTS към масива от елементи. С други думи, всички промени, които правите в newItems, ще засегнат директно масива от елементи.

плътност на прагмата ^ 0.4.17;
договор плодове {
    string [] публични елементи;
    constructor () public {
        items.push ( "ябълка");
        items.push ( "оранжево");
        string [] storage newItems = елементи;
        newItems [1] = 'лимон';
    }
}
// елементи [1] вече ще бъдат лимони
// елементи [0] ще останат същите като „ябълка“

В заключение ключът за съхранение принуждава новосъздадената променлива да сочи променливата на състоянието (елементи), а не копие. Всички промени, направени в новата променлива, ще променят директно структурата на променливата на състоянието на договора.

NewItems като памет

newItems има алтернативен метод за постоянство. Вместо за съхранение има опция за памет. Опцията памет функционира като копие за разлика от указател. По този начин използването на ключа за памет и извършването на мутации върху новосъздадената променлива НЯМА да повлияе на променливата на първоначалното състояние. Пример по-долу.

плътност на прагмата ^ 0.4.17;
договор плодове {
    string [] публични елементи;
constructor () public {
        items.push ( "ябълка");
        items.push ( "оранжево");
        string [] памет newItems = елементи;
        newItems [1] = 'лимон'
    }
}
// елементи [1] ще останат същите като „оранжево“
// елементи [0] ще останат същите като „ябълка“

заключение

Надявам се това да реши всеки въпрос относно това предупреждение относно паметта спрямо съхранението. Гледам съхранението (състояние) като твърд диск, а паметта (локални променливи, временни) като RAM. Ако очаквате да създадете функции, които правят промени в състоянието, съхранението може да е най-добрият вариант. Ако имате нужда от копие на данните, но не е задължително да искате да манипулирате паметта на състоянието на договора, използвайте паметта.

Странична бележка

Всяка стойност, предадена във функция на договор, ще бъде изпратена през паметта (по подразбиране). Функция, която приема този параметър, няма да манипулира състоянието на договора. Пример по-долу.

плътност на прагмата ^ 0.4.17;
договор плодове {
    string [] публични елементи;
    constructor () public {
        items.push ( "ябълка");
        items.push ( "оранжево");
        
        changeFirstElement (елементи);
    }
    
    функция промянаFirstElement (string [] newItems) чист частен {
        newItems [0] = 'лимон';
    }
}
// елементи [1] ще останат същите като „оранжево“
// елементи [0] ще останат същите като „ябълка“

Ако трябва да наложите промяна в състоянието, можете да добавите ключа за съхранение в параметъра.

функция промянаFirstElement (string [] съхранение newItems) частен {
        newItems [0] = 'лимон';
}

перка