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 {
//changed code to directly assign the new balace to the mapping
users[id].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 balance) {
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;
}
}
changing the data location from memory to storage on the updateBalance function was what was required to fix the issue. due to “memory” only being saved during that function and “storage” is permanent.
I know this is not correct, but not fully understanding why. I thought that the user mapping member has storage scope by default ??
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;
}
}
ok look like it was correct and I was not clicking the buttons from the newly deployed contract
Changed the update function to
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 {
require(users[id].balance > 0, "Balance is zero");
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
I had changed:
function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
}
to:
function updateBalance(uint id, uint balance) public {
require(users[id].balance > 0, "Balance is zero");
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);
}
//a simple change to the code would be to change the data location from 'memory' to 'storage' like this....
function updateBalance(uint id, uint balance) public {
User storage user = users[id]; //this had 'memory' instead of 'storage' meaning the data was discarded after the function finished executing.
user.balance = balance;
}
//we could have just removed the need for the temporary variable called 'user' and updated the balance directly by just having the following single statement within the function body:
// ===>>> users[id].balance = balance; <<<===
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
Hi @Emmett,
Yes, your solution is correct, and for the reason you thought: the mapping users
has a data location of storage
by default, and so any data assigned to it will be stored permanently.
Your solution in terms of the following line of code, is correct:
I think that with this require()
function…
… you are maybe trying to prevent balances being updated for users that haven’t yet been created. Is that correct? If so, then the problem with doing it this way, is that it also prevents users whose balance is currently 0 from having their balances updated.
The functionality you are trying to add is very much needed. Can you think of an alternative way to code it, so that it doesn’t have this unwanted side-effect?
My solution: in updateBalance set user in storage and it works:
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 set user in the updateBalance function from memory to storage and it worked, but this seems to simple. I may post an updated version of this code after watching the solution video.
pragma solidity 0.6.6;
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;
}
}```
Yep, that is correct.
I wanted to play with the require() function. The next step is to figure out a condition like bool userCreated = true and put that inside require().
user is kept in memory.
Simpler to change directly in storage:
users[id].balance = balance;
Question: In our program, does the functioeatePerson() inserted a new person into an array or does it override the previous struct?
I was trying to return a person by ID, but it didn’t work.
Are you referring to the MemoryAndStorage contract that we built specifically for this Data Location Assignment, or our original HelloWorld contract? The reason I ask, is because in the contract for this assignment the function you are referring to is addUser()
. The createPerson
function is in HelloWorld…
If you are referring to the contract MemoryAndStorage, then addUser()
doesn’t insert a new person into an array, because we don’t have an array in this contract. Instead, it assigns the new user to the mapping users
in the following line:
users[id] = User(id, balance);
This is a more concise way of doing the following:
User memory newUser;
newUser.id = id;
newUser.balance = balance;
users[id] = newUser;
In this more long-winded code, you can clearly see that we are not overwriting the User struct. We are using the User struct like we do a class in JavaScript. Structs and classes are like templates or blueprints from which we can create new object instances to which we assign data on an instance by instance basis. User
here acts like a data type, in the same way as uint
or string
or address
. So in the same way that we declare a new local variable with a string data type, as follows:
string memory name;
… we can also create a new local instance with the same data structure as the User struct blueprint, as follows:
User memory newUser;
I need you to confirm which contract you are referring to before I can answer this question.
I have a solution based on using a Boolean true
for new users created, and I then used this in the require() function to set a constraint, just like you’ve suggested. Feel free to come up with your own solution and post it here together with any comments or observations. I’ll take a look at it and share my own solution if it uses a different method.
It’s great to see you so enthusiastic about experimenting further with the code from the lectures and assignments. You’re learn a lot that way.
I had added bool isCreated
state variable. Function updateBalance()
will not execute if users[id].isCreated == false
.
Also, the function getBalance()
returns false if the User haven’t been added.
pragma solidity 0.5.1;
contract MemoryAndStorage {
mapping (uint => User) users ;
struct User{
uint id;
uint balance;
bool isCreated;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance, true);
}
function updateBalance(uint id, uint balance) public {
require(users[id].isCreated == true, "User does not exist");
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint, bool) {
return (users[id].balance, users[id].isCreated);
}
}
I was referring to contract HelloWorld where we built struct Person
.
function insertPerson(Person memory newPerson) private {
address creator = msg.sender;
people[creator] = newPerson;
}
Does this function override the Person struct each time for same address?
I had added uint id
for an ability to getPerson()
by id. It didn’t work.
I’ve gotten the first person created each time.
Changed “User memory user = users[id];” to “User storage user = users[id];”
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;
}
}