just added
users[id] = user;
so, it would save the updated balance from the temporary struct of “user” that’s created inside the updateBalance function into the mapping for permanent use.
just added
users[id] = user;
so, it would save the updated balance from the temporary struct of “user” that’s created inside the updateBalance function into the mapping for permanent use.
that’s dope! Nice way to streamline it.
User storage user = users[id];
I removed "User memory user = users[id]; and replaced it with the one above in the updateBalance function. In that way I stored the vaue in storage instead of memory so it isn’t dissappearing after it has been executed. It worked, but I hope it was an ok solution
Hi @ibin,
This line provides a good solution to the problem
But the compiler throws an error with your addition #1. Are you trying to add functionality that will only allow the balance to be updated for existing users? If you are, then I would suggest the implementation below.
Also, using conditional execution (an if
statement) is inappropriate if my understanding of what you are trying to achieve is correct. Instead, you want to use require()
in order to revert the transaction if the user does not already exist. With an if
statement, the transaction is still executed whether the condition is met or not, even though the balance itself won’t be updated by creating a new user if the user doesn’t already exist (like it was before).
pragma solidity 0.5.1;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User {
uint id;
uint balance;
bool state;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance, true);
}
function updateBalance(uint id, uint balance) public {
require(users[id].state, "To update balance, user must already exist");
users[id].balance = balance;
}
function getBalance(uint id) view public returns(uint) {
return users[id].balance;
}
}
function updateBalance(uint id, uint balance) public {
users[id].balance = 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 {
User memory user=users[id];
user.balance=balance;
users[id]=user;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
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 storage user = users[id];
user.balance = 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 {
User storage user = users[id];
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
I would change ‘memory’ to ‘storage’ in the update balance function. This would enable the data to be stored in a “persistent” location, which would allow it to remain and be reflected in the new balance after the function has been called.
Change:
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
pragma solidity 0.5.12;
contract MemoryandStorage {
struct User{
uint id;
uint balance;
}
mapping(uint => User) users;
function addUser(uint id, uint balance) public {
users[id] = User(id, balance); //creating a user
}
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
I tested out deploying and running this contract. I was able to add users, update balance, and get balance for different id numbers. It all worked well.
changing “User memory user” to “User storage user” does the trick.
Following change is required in updateBalance function,
Change line 17 in the contract. Changing storage location from “memory” to “storage” will not create a new copy of data, rather it will create a pointer to storage. Hence any change in user object will be reflected in the storage itself.
User storage user = users[id];
I didn’t understood the last part, can you please explain me your logic again…what do you mean by “user” created inside the updateBalance function into the mapping for permanent use ?
Basically we had used the following line : users[id] = user; in add function which takes id, balance arguments. So, once its executed it will hold id, balance data. But further when control comes in updateBalance function, how is data & control flow happening ? Below is my understanding as mentioned in “code comments”, please correct me.
updateBalance(uint id, uint balance) public {
User memory user = users[id]; //user created in separate “memory” and its data(id, balance) is utilized.
user.balance = balance; //balance is updated
users[id] = user; //users[id] is referencing addUser function & its equating to “user”
} // So, how is the “users” updated with current updated data ?
We could change
User memory user = users[id];
into
User storage user = users[id];
so that the the data will be permanently stored and tweaked instead of creating new copies in memory.
Hi @Nityam_Jigyasu,
This line of code (within the updateBalance function in the contract posted by @Nile) isn’t referencing the addUser function.
mappingName[key] = value;
is the syntax used to assign a value to a specific key in a predefined mapping. So in our case:
users
id
user
** user
is a temporary instance of the User
struct created locally within the updateBalance function and stored in memory. When user
is assigned to our users
mapping for permanent storage (in the 3rd line of the updateBalance function body) it already has the following properties (key/value pairs):
user = {
id: idEnteredByUser,
balance: balanceEnteredByUser
};
So these are the key/value pairs which are now assigned permanently to our users
mapping, and mapped to the specific key idEnteredByUser
, which can now be used to retrieve this particular user’s data at any time by using the following syntax:
users[idEnteredByUser].balance // => balanceEnteredByUser
I hope this explanation now clarifies for you what’s actually happening in the code @Nile has posted. But let us know if anything still isn’t clear, or if you have any further questions
Yes, I understood now, thank you for your explanation. It helps a lot. I just have a question regarding the first line :
mapping(uint => User) users;
//In the Chpt 5: “Introduction to Mappings” lecture there are 2 ways syntax is mentioned:
mapping(keyType =>valueType) name
mapping(address => uint) balance
So, how do I interpret the first line : mapping(uint => User) users;
According to my understanding, uint is the keytype and User is the valueType and users is the name of the mapping.
why do we use “uint” as key and User as value? as you explained that mappingName[key] = value is how the syntax is. Isn’t “uint” keyword and can we use the keyword name to define it ?
Like in C++, Java, we don’t use keywords as variable name, mapping name …etc
Thank you
I did the simple solution of using storage instead of memory in User memory user = users[id];
pragma solidity 0.5.1;
contract MemoryAndStorage {
mapping(uint256 => User) users;
struct User {
uint id;
uint balance;
}
function addUser(uint256 id, uint256 balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint256 id, uint256 balance) public {
User storage user = users[id];
user.balance = balance;
}
function getBalance(uint256 id) view public returns (uint) {
return users[id].balance;
}
}
The user[id] must be updated with the new balance:
function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
users[id] = User(id, balance);
}
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 storage user = users[id];
user.id = id;
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}