Changing data location from “memory” to “storage”, therefore the data updated is stored permanently and still remain after the function call.
So change this line,
User memory user = users[id];
with this line,
User storage user = users[id];
Changing data location from “memory” to “storage”, therefore the data updated is stored permanently and still remain after the function call.
So change this line,
User memory user = users[id];
with this line,
User storage user = users[id];
Hi @Nityam_Jigyasu,
Many apologies! I started writing a response to your additional question, but I’ve only just realised I hadn’t finished writing it
Correct
Here, we are defining our mapping with the name users
. And then, in the same way that we declare the type of data we are storing in our state variables (e.g. uint id;
or address owner;
) here we do the same and declare the type of data our keys and their associated values will be, in preparation for actual assignment later.
Maybe what is confusing is the fact that, as a mapping is a data structure, we actually need to declare three data “types” (actually 1 data structure which contains 2 data types), whereas with a state variable we only need to declare 1 data type i.e.
// Mapping // State variable
mapping(uint => User) users; uint height;
// 3 2 1 N 1 N
/* 1 data type of the value
2 data type of the key
3 data structure type
N name of the mapping or variable */
I hope that makes it clearer. But do let us know if there is still something that doesn’t make sense.
Hi @Lunasea,
Your code works, but all you are doing in the additional line of code is repeating the functionality of the addUser
function. This makes the previous two lines superflous i.e. they can be removed as they don’t affect the third line that you’ve added.
However, instead of updating both the ID and the balance, we only want to use the updateBalance
function to update balances of existing users. The ID will already have been assigned in the addUser
function and, by its very nature, won’t need to be updated like the balance. We only need to include the ID as an input parameter in order to be able to map the new balance to the correct user.
So we only want to update the mapping’s permanent storage with a user’s new balance, which can be achieved by either:
function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
users[id] = user;
}
or
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
I hope that’s clear. Just let us know if you have any questions.
Keep on learning!
Hi @Li_Sun,
Your solution works, but you can remove the following line of code from your updateBalance
function:
user.id = id;
Assuming we are only going to use this function to update balances of existing users, the user ID will already have been assigned in the addUser
function. And so the above additional line of code is unnecessary. We only need to include the ID as an input parameter in order to be able to map the new balance to the correct user.
I hope that is clear. Let us know if you have any questions.
Keep on learning!
Thank you very much, It helps in understanding mapping data structure. Actually, spending more time behind understanding internal working and behavior helps before we deep dive and move ahead working on professional projects. Thanks again.
Change the original function:
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
To:
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
The balance was being held in memory so was never being updated to the storage when you change User memory user = user[id] to User storage user = user[id] the balance will get updated in the memory.
Hi There
Simple method to fix code…
pragma solidity 0.5.1;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
/// fixed missing update
users[id] = User(user.id,user.balance);
///
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
pragma solidity 0.5.1;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
I’ve tried running the code I’ve seen in a lot of answers. I understand the tweak, that memory needs to be changed into storage because it changes the state of the function from temporary to permanent.
However when I run 1,10 -> addUser ->getBalance -> I get string 0
and when I addbalance 1,20 ->getbalance -> I still get string 0
Can anyone explain to me why I’m not getting the desired answer? I’ve tried putting it in “quotationmarks” and it still gives me the same result
pragma solidity 0.5.1;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public{
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
@filip
Hi. I had to change pragma solidity to 0.5.12 otherwise with google-chrome it won’t compile.
To differentiate addUser and updateBalance I added some constraint.
pragma solidity 0.5.12;
contract MemoryAndStorage {
mapping(uint => User) users; struct User{ uint id; uint balance; } modifier newUser(uint id) { require( id > 0, "User id must be > 0" ); require( id != users[id].id, "User id is already used" ); _; } modifier userMustExist(uint id) { require( id > 0, "User id must be > 0" ); require( id == users[id].id, "User doesn't exist" ); _; } function addUser(uint id, uint balance) public newUser(id) { users[id] = User(id, balance); } function updateBalance(uint id, uint balance) public userMustExist(id) { //User memory user = users[id]; //user.balance = balance; //users[id] = User(id, balance); // First solution users[id].balance = balance; } function getBalance(uint id) view public userMustExist(id) returns (uint) { return users[id].balance; }
}
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
Hi @JeffE,
I think you meant to say: “… the balance will get updated permanently in storage”.
function updateBalance(uint id, uint balance) public {
User memory newUser;
newUser.balance = balance;
users[id] = newUser;
The function is assigning a copy of the User to memory from the mapping and updating the balance of the copy. The copy is then destroyed after execution of the function. To persist the balance, one way is to directly update the balance of the User referenced by the mapping:
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
Since users was already in storage just need to replace the current balance of the index of id in users to the new balance. There shouldn’t be a need to use memory or any extra variables, right?
pragma solidity 0.5.1;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
users[id].balance= balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
Hi, I change memory to storage in the following function to have the modification be stored after the function runs:
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
function updateBalance(uint id, uint balance) public {
//User memory user = users[id];
users[id].balance = balance;
}
Just need to change the users[id] balance directly. Commented out the other section.
pragma solidity 0.5.12;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
// User memory user = users[id];
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}