40

If I have a mapping of string => custom defined struct, how do I check if a value is defined in the mapping?

The docs state that "every possible key exists and is mapped to a value whose byte-representation is all zeros".

What is the zero-value of a custom defined struct such that one can conditionally check for its existence?

  • Yes indeed. Thanks Should i delete the topic ? – beginerether Feb 5 '16 at 18:58
  • No, only off-topic or unintelligible questions should be deleted. Duplicates are quite useful to keep around as there are multiple ways to phrase a question. – Joris Bontje Feb 5 '16 at 19:11
33

You check that a value is defined in the mapping by checking it is not zero.

If an explicit setting of zero has meaning for your application, you need auxiliary data (or structure) to track when a value of zero has been explicitly set.

A lightweight approach would be to add a bool property to the struct (say named initialized), and to set it to true when the zero is explicitly set. As all bools are false (0) by default, you can check against the value true.

Alternatively, check that each member of the struct is zero. If a member is a string, cast it to bytes and then check its length is zero.

For an example see How to test if a struct state variable is set

Another data structure or mapping may be needed depending on the application.


Here is a related example on using a pair to check the meaning of zero:

contract C {
    uint[] counters;
    function getCounter(uint index)
        returns (uint counter, bool error) {
            if (index >= counters.length) return (0, true);
            else return (counters[index], false);
        }
    function checkCounter(uint index) {
        var (counter, error) = getCounter(index);
        if (error) { ... }
        else { ... }
    }
}
  • 3
    To clarify (because this differs from the other languages that I work in), I can check for structMapping[key].initalized == false even when that key has not been defined in the mapping? – Thomas Clowes Feb 3 '16 at 9:15
  • 4
    Yes, the default value for everything in the Ethereum Virtual Machine (which Solidity is based on) is zero. (Anything uninitialized is zero, unlike other languages where values may be "garbage".) – eth Feb 3 '16 at 9:49
  • Would it be possible to use a string instead of a bool? (saying: I have an enum for which I have only string properties) Then: with what should you compare the string struct with? (in other words: what is the default value for a string) – lajarre Jun 5 '16 at 17:56
  • @lajarre Good you asked ethereum.stackexchange.com/questions/5683/… – eth Jun 6 '16 at 4:15
  • Being able to test the value of arbitrary members before knowing whether the struct is initialised also means you might not even need to know the answer to that question in the first place – you can just go around assigning members right away. I know, I'm already feeling the slap of the segfault on my face too, but Solidity is its own beast. – David Ammouial May 15 '17 at 22:58
7

There's really no such thing as "empty". An uninitialized index of the mapping is simply equal to the " zero" value of the proper type.

To check if a value has been assigned, just check if balances[msg.sender]== 0. If a user accesses the contract, but the balance should be 0, you can use a address => int256 mapping, and use -1 for 0 balances

1
function checkArray(bytes a) returns (bool){
    if ((a) && (a.length > 0))
        return true;
    return false;
}
  • 1
    Give me an error: Operator && not compatible with types bytes memory and bool solidity 0.4.7 – atomh33ls Jan 10 '17 at 21:06
0

For an unsigned index value of an array of struct (say Customer)- to check if the entry exists in given array of structs, you can do something like below:

 struct Customer {
    string userName;
    string dataHash;
    address bank;
    int256 upVotes;
}

Customer[] public customers; 

...
//assuming we have some customers added (customers.length>0)
...

function getCustomerIndex(string memory userName) internal view returns(bool, uint256) {
    for(uint i=0; i<customers.length; i++) {
        if (stringEquals(customers[i].userName, userName)){
            return (true, i);
        }
    }
    return (false, 0);
}

The explicit (false, 0) suggests that the customer with given username is not found in the customers struct array.

Now in my other code I can use the above function as follow:

// return 1 implies customer found and removed from struct Customer array
// return 0 implies no customer found in the struct Customer array
function removeCustomer(string calldata userName) external returns (uint8) {
        (bool result, uint256 index) = getCustomerIndex(userName);
        if (result){
            for (uint i=index+1; i<customers.length-1; i++){
                customers[i-1] = customers[i];
            }
            customers.length--;
            return 1;
        }
        return 0;
    }

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.