Solidity хранит указатель хранилища в переменной хранилища для доступа к нему из разных функций.

Можно ли в контракте, используя Solidity, сохранить указатель на переменную хранения в переменной хранения (или где-то еще, что может быть подходящим) и получить к ней доступ из отдельных функций?

Рассмотрим следующий пример в псевдокоде Solidity:

contract AContract {

    struct AStruct { 
      uint a_field;
    }

    AStruct variable_a;
    AStruct variable_b;

    AStruct storage pointer_to_either_a_or_b;

    modifier AModifier()
    {
      if (condition_a)
      {
        pointer_to_either_a_or_b = variable_a;
      }
      else
      {
        pointer_to_either_a_or_b = variable_b;
      }
    }

    function AFunctionUsingPointerToAorB100() internal AModifier()
    {
      pointer_to_either_a_or_b.a_field = 100;          
    }

    function AFunctionUsingPointerToAorB200() internal AModifier()
    {
      pointer_to_either_a_or_b.a_field = 200;          
    }

}

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

Ошибка: ожидаемый идентификатор, получено «Хранилище»

Есть ли способ обойти это, например, поместив указатель в другое место в коде?

Переменные состояния ВСЕГДА являются переменными хранения, поэтому вы не можете добавить их в хранилище AStruct pointer_to_either_a_or_b; декларация. Это уже переменная хранения.

Ответы (1)

Удаление ключевого слова storage at AStruct storage pointer_to_either_a_or_b;устранит ошибку (поскольку переменные состояния всегда имеют значение storage ), но вы не сможете добиться того, что пытаетесь сделать.

Причина в том; поскольку AStruct pointer_to_either_a_or_b;это переменная хранения, присвоение ей значения создаст независимую копию, а не ссылку на variable_aили variable_b. Это упоминается в документах Solidity здесь ,

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

Я не знаю, каково ваше фактическое требование, но в зависимости от того, что вы разместили здесь, я не буду использовать модификатор (и никаких указателей), но попробую что-то вроде этого,

function sample(uint _val) public // val = 100 or 200
 {
      if (condition_a)
      {
        variable_a.a_field = _val;
      }
      else
      {
        variable_b.a_field = _val;
      }
}

Надеюсь это поможет!

К вашему сведению: насколько я знаю, локальные переменные, объявленные внутри модификаторов, недоступны внутри функции.

Спасибо за ваш ответ. Я подозревал, что невозможно получить доступ к общему указателю на переменную хранения в отдельных функциях. Фактическое требование состоит в том, чтобы иметь набор из множества функций, выбирающих отдельную переменную в качестве вывода в зависимости от заданного условия. Я думал о модификаторах как о гипотетически хорошем варианте для создания указателя на эти выходные переменные, но, как вы заявили, невозможно получить доступ к переменным, объявленным внутри модификаторов внутри функций.
Скорее всего, мне придется использовать что-то похожее на ваше предложение, например, использовать дополнительную функцию для возврата указателя: function Greeter_a(uint _val) public // val = 100 or 200 { GetPointer().a_field = _val; } (...) function Greeter_x(uint _val) public // val = 100 или 200 { GetPointer().x_field = _val; } функция GetPointer() public возвращает (хранилище VariableType) { if (condition_a) { return variable_a; } иначе { вернуть переменную_b; } }
Боюсь, вы можете сделать это, getPointer()потому что возвращаемое значение будет копией переменной, и оно не будет указывать на переменную состояния и изменять ее.
При добавлении ключевого слова «хранилище» к «возвратам» оно действительно возвращает ссылку на переменную хранилища, например указатель. Итак, «возврат (хранилище VariableType)» работает.