Tengo curiosidad por saber qué sucede si intentas hacer lo siguiente:
contract C {
Struct S {
uint a;
uint b;
}
mapping(address => s) structs;
function updateStructs(S sInstance) private {
structs[msg.sender] = sInstance;
}
function addStruct (uint _a, uint _b) payable {
S memory s = S({a: _a, b: _b});
updateStructs(s);
}
}
Como entendí cómo funcionan las variables, addStruct crea una variable de memoria que solo tiene un alcance de función y se desasignará una vez que se procese esta transacción/mensaje. Entonces, ¿qué quedará structs[msg.sender]
después de llamar a addStruct? ¿Será cambiar updateStructs(S sInstance)
para updateStructs(S storage sInstance)
cambiar algo?
Cuando almacena una variable de memoria en el almacenamiento, simplemente copiará el objeto en el almacenamiento.
El uso de la palabra clave de almacenamiento en updateStructs en realidad no hará nada. Las estructuras y matrices en las funciones son variables de almacenamiento predeterminadas, por lo que el objeto de memoria se copiaría en el almacenamiento justo cuando llama a updateStructs sin la palabra clave de almacenamiento.
Editar: estoy corregido. @LibertyLocked tiene razón en su respuesta donde dice que no puede convertir implícitamente de memoria a almacenamiento, por lo que agregar la palabra clave de almacenamiento al argumento hará que la compilación falle.
En su ejemplo, si cambiara su código para que se vea así
function updateStructs(S storage sInstance) private {
structs[msg.sender] = sInstance;
}
function addStruct (uint _a, uint _b) payable {
S memory s = S({a: _a, b: _b});
updateStructs(s);
}
El código no se compilará por las siguientes razones:
updateStructs
espera una instancia de estructura del almacenamiento, pero le está pasando una instancia de estructura en la memoria.s
almacenamiento addStruct
.S memory sInstance
en su updateStruct
, su s
se copia en el marco de pila de updateStructs
. Además, la s
entrada addStruct
no se desasigna hasta que regresa de addStruct
(de lo contrario, ¿cómo continuaría ejecutándose la función una vez que regresa de updateStruct
?).Para responder a su pregunta, en su ejemplo debe usar memory
en lugar de storage
. De hecho, está implícitamente memory
en los argumentos de función.
S memory s = S({a: _a, b: _b});
la variable de memoria se creará en el alcance de addStruct
, luego, en updateStructs(s);
el valor de s
se copia en el marco de la pila de updateStructs
y luego s
se copia del marco de la pila en el almacenamiento en structs[msg.sender] = sInstance;
, ¿verdad? Mi pregunta era qué habrá en este lugar en el almacenamiento.structs[msg.sender]
. Solo se modifica en updateStructs
. storage
palabra clave significa una referencia a la ubicación de almacenamientos
en updateStructs
la pila y s
mantiene la referencia a esos bytes. Una vez que haces structs[msg.sender] = sInstance
lo que sucede? Si se copia la referencia s
, no tiene ningún sentido, ya que los bytes asignados a la pila son válidos solo en el ámbito de la función y structs[msg.sender]
apuntarán a bytes aleatorios según el nodo en el que se ejecute. Si los bytes asignados de la pila se copian structs[msg.sender]
, está bien, pero aún no obtuve confirmación de esto de sus respuestas.
libertad bloqueada
s
no se desasigna hasta queaddStruct
regresa. Puede ser útil comprender los marcos de pila o los registros de activación.