Ошибка Solidity: структура, содержащая (вложенное) сопоставление, не может быть построена

Моя версия solc:

"solc": "^0.7.1",

Когда я пытаюсь создать структуру, содержащую сопоставление, я получаю эту ошибку: «Структура, содержащая (вложенное) сопоставление, не может быть построена»

Это мой код солидности.

Кампания.sol

pragma solidity >=0.5.0;

contract Campaign {
    struct Request {
        string description;

        // I declared a mapping inside of a struct.
        mapping(address => bool) approvals;

    }
    constructor(uint256 minimum, address creator) {
        ...
    }

    function createRequest(string memory description) public onlyManager {
        Request memory newRequest = Request({ 

            // Here the compiler gives me an error

            description : description

        });
    }
    ...

Это говорит

Struct containing a (nested) mapping cannot be constructed.

Пожалуйста, помогите мне.

Вы не можете создать сопоставление (или структуру, содержащую его) в памяти.
@goodvibration Я также пробовал хранилище и просто «Запросить новыйЗапрос». Но выдает ту же ошибку
Поскольку ничто в вашем коде не говорит о том, что вам вообще нужна эта структура, самым простым решением было бы просто избавиться от нее.
Хранилище предназначено для существующих предметов, а не для новых!
Ага, тогда как мне создать свой запрос с заданной переменной (в данном случае описанием)?
Как я уже сказал - во-первых, в вашем коде нет ничего, что предполагало бы, что вам вообще нужна эта структура для начала. Так что либо объясните, зачем именно вам это нужно, либо просто избавьтесь от него совсем. Во-вторых, даже если вы объясните, зачем вам это нужно, вам все равно нужно объяснить, почему вам нужно отображение внутри него. Потому что если вы этого не сделаете, то вы можете (и должны) просто объявить отображение вне структуры, а не внутри нее. Пожалуйста, исправьте свой вопрос, чтобы он имел смысл!
Это потому, что мне нужно проверить, проголосовал ли каждый из запросов или нет. Я хочу создать функцию голосования в своем смарт-контракте. Поэтому я сделал сопоставление (адрес => логическое значение), чтобы проверить, является ли адрес из одного конкретного запроса истинным или нет.
@goodvibration Это действительно работало до solidity version 7.0, когда pushиспользовалось

Ответы (6)

Проблема в конструкции, т.е. Request({ description: description })поэтому смена расположения newRequestс memoryна storageне поможет.

Если вы действительно хотите, чтобы это работало, создайте переменную состояния, скажем, mapping (uint => Request) requests. Теперь внутри вашей функции вы можете написать, Request storage newRequest = requests[index]где indexбудет увеличиваться позже.

Для справки см.: документы

Большое спасибо! Тогда есть ли способ поместить определенный адрес (из структуры запроса) в ключ (вместо uint) сопоставления?
Вы можете изменить его наmapping(address => Request)
Спасибо за вашу помощь. Я постараюсь.
Где вы устанавливаете сопоставление для approvals? @hrkrshnn
@alper, вы на самом деле не устанавливаете сопоставление для утверждений. Если вы определили локальную структуру внутри функции, она должна быть указателем на структуру хранения.

с 0.7.0 сделайте как показано ниже:

 struct Request{
            string description;
            uint value;
            address recipient;
            bool complete;
            uint approvalsCount;
            mapping(address => bool) approvals;
        }
        
    uint numRequests;
    mapping (uint => Request) requests;
    
    function createRequest (string memory description, uint value,
            address recipient) public{
                Request storage r = requests[numRequests++];
                r.description = description;
                r.value = value;
                r.recipient = recipient;
                r.complete = false;
                r.approvalsCount = 0;
            
        }
При этом я получил ошибку: Ошибка типа: местоположение данных может быть указано только для типов массива, структуры или сопоставления, но было указано «хранилище».
Как насчет сопоставления утверждений в структуре запроса? Как вы можете обновить это?

Этого должно быть достаточно:

function createRequest(string memory description) public onlyManager {
    Request storage newRequest = requests.push();
    newRequest.description = description;
}

Ваше здоровье!

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

Итак, преобразуйте свой код из этого:

contract Campaign {
    struct Request {
        string description;
        uint value;
        address recipient;
        bool complete;
        uint approvalCount;
        mapping(address => bool) approvals;
    }

    Request[] public requests;

    function createRequest(string memory description, uint value, address recipient) public restricted {
      Request memory newRequest = Request({
          description: description,
          value: value,
          recipient: recipient,
          complete: false,
          approvalCount: 0
      });
      requests.push(newRequest);
    }
}
    

к этому

contract Campaign {
    struct Request {
        string description;
        uint value;
        address recipient;
        bool complete;
        uint approvalCount;
        mapping(address => bool) approvals;
    }
    
    uint numRequests;
    mapping (uint => Request) requests;
    
    function createRequest(string memory description, uint value, address recipient) public restricted {            
        Request storage r = requests[numRequests++];
        r.description = description;
        r.value = value;
        r.recipient = recipient;
        r.complete = false;
        r.approvalCount = 0;
    }
}

Ссылка

Я хочу добавить некоторую справочную информацию, чтобы помочь тем, кто переходит от среды с управляемой памятью (например, .NET CLR) к EVM:

  • Обычно у вас могут быть экземпляры ссылочных типов, которые выделяют память (в куче). Поскольку память Solidity EVM более ограничена, вместо этого Solidity инициализирует сопоставления в хранилище контрактов (вместо памяти ). Поскольку создание экземпляра a structв стеке использует memory, вот почему это сообщение об ошибке появляется при попытке создать экземпляр Solidity struct, который содержит mapping.
  • Обычно вы можете запросить у среды выполнения новую память (например, используя newключевое слово в C#). В Solidity этот шаг абстрагируется от разработчика, вместо этого Solidity EVM автоматически делает это за нас за кулисами. В частности, это происходит при mappingобъявлении переменной. Вот почему в примерах кода на этой странице не показан этап выделения памяти, а вместо этого просто сразу переходите к настройке mappingзначений.

Вы не можете создать structс отображением внутри. Создайте локалку mappingв своем контракте на верхнем уровне.

Спасибо! Как я могу связать сопоставление с конкретным запросом? Потому что я хочу проверить, проголосовал ли запрос или нет (как True или False)
Используйте общий идентификатор. Вы сохраняете сопоставление с идентификаторами и сопоставление с идентификаторами для структур.