7

So, I want to fill an array of a struct residing in an array of another struct:

...

struct Answer
{
    bytes32 name;   // short name (up to 32 bytes)
    uint voteCount; // number of accumulated votes
}

struct Question
{
    bytes32 name; // short name (up to 32 bytes);
    Answer[] answers;
}

Question[] public questions;
...

i want to add a question with an array of answers the following way

function addQuestion(bytes32 _name, bytes32[] _answers) onlyOwner {
    Answer[] memory answersLocal = new Answer[](_answers.length);

    for (uint i = 0; i < _answers.length; i++) {
        answersLocal[i] = Answer({
            name: _answers[i],
            voteCount: 0
        });
    }

    questions.push(Question({
        name: _name,
        answers: answersLocal
    }));
}

the compiler complains:

Copying of type struct Roadshow.Answer memory[] memory to storage not yet supported.

Does anyone have an idea how can i get this done?

11

The compiler is complaining because you've wandered into reference variables. Not to worry, we don't want to be there.

Another issue is you've got a dynamic array in the function arguments. It's not possible because the interface doesn't support it. That's okay, too. We don't want that either.

We need to break it down so we're only ever passing in fixed size, non-complex values, which means tiny single-purpose functions.

I ended up restructuring the storage to a layout I think is more appropriate. Then created some exemplary functions to work with the data.

  • Insert question
  • Insert answer
  • Get question by key
  • Get answer by question key and answer key
  • Get question count
  • Get question key by row number
  • Get answer count for a question by question key
  • Get answer key for a question by question key and row number

Here's a way to combine structs with arrays and mappings in a way I think is a good start given the one-to-many Q&A relationship. And, some examples of simple functions that don't pass arguments that are too complex for Solidity.

No warranty, but hopefully this gives you some ideas.

    pragma solidity ^0.4.6;

    contract Quiz {

    struct Answer
    {
        bytes32 text; 
        uint voteCount; // number of accumulated votes
        // add more non-key fields as needed
    }

    struct Question
    {
        bytes32 text;
        bytes32[] answerList; // list of answer keys so we can look them up
        mapping(bytes32 => Answer) answerStructs; // random access by question key and answer key
        // add more non-key fields as needed
    }

    mapping(bytes32 => Question) questionStructs; // random access by question key
    bytes32[] questionList; // list of question keys so we can enumerate them

    function newQuestion(bytes32 questionKey, bytes32 text) 
        // onlyOwner
        returns(bool success)
    {
        // not checking for duplicates
        questionStructs[questionKey].text = text;
        questionList.push(questionKey);
        return true;
    }

    function getQuestion(bytes32 questionKey)
        public
        constant
        returns(bytes32 wording, uint answerCount)
    {
        return(questionStructs[questionKey].text, questionStructs[questionKey].answerList.length);
    }

    function addAnswer(bytes32 questionKey, bytes32 answerKey, bytes32 answerText)
        // onlyOwner
        returns(bool success)
    {
        questionStructs[questionKey].answerList.push(answerKey);
        questionStructs[questionKey].answerStructs[answerKey].text = answerText;
        // answer vote will init to 0 without our help
        return true;
    }

    function getQuestionAnswer(bytes32 questionKey, bytes32 answerKey)
        public
        constant
        returns(bytes32 answerText, uint answerVoteCount)
    {
        return(
            questionStructs[questionKey].answerStructs[answerKey].text,
            questionStructs[questionKey].answerStructs[answerKey].voteCount);
    }

    function getQuestionCount()
        public
        constant
        returns(uint questionCount)
    {
        return questionList.length;
    }

    function getQuestionAtIndex(uint row)
        public
        constant
        returns(bytes32 questionkey)
    {
        return questionList[row];
    }

    function getQuestionAnswerCount(bytes32 questionKey)
        public
        constant
        returns(uint answerCount)
    {
        return(questionStructs[questionKey].answerList.length);
    }

    function getQuestionAnswerAtIndex(bytes32 questionKey, uint answerRow)
        public
        constant
        returns(bytes32 answerKey)
    {
        return(questionStructs[questionKey].answerList[answerRow]);
    }  
}

A notable shortcoming with this example is it isn't checking if keys exist or enforcing uniqueness. I left that out for brevity but it's easily added to this pattern. More details here. https://medium.com/@robhitchens/solidity-crud-part-1-824ffa69509a#.gvh9pf1gj

Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.