¿Cómo paso por referencia?

Tengo un par de preguntas.

Primero:

Entonces, en una función, creé una matriz de memoria. Quiero pasar esta memoria por referencia a otra función..

function test2() public returns(uint  a) {
        uint[2] memory gio;
        gio[0] = 100;
        gio[1] = 200;
        test3(gio);
        return gio[0];
    }
    
    
    function test3(uint[2] storage arr) private returns (uint) {
        arr[0] = 35;
    }

Esto no funciona y dice:

Tipo no válido para el argumento en la llamada de función. Se solicitó una conversión implícita no válida de la memoria uint256[2] al puntero de almacenamiento uint256[2]. prueba3(gio); ^-^

¿No es posible?

Segundo

las funciones internas y privadas son los únicos tipos de funciones que pueden recibir parámetros como tipos de referencia, ¿verdad? ya que las funciones públicas y externas que se llaman pueden depender de otra aplicación, por lo que otra aplicación no puede pasar parámetros como referencias. Acordado ?

tercero _

string test;
   
    function test2() public returns(uint  a) {
        test = " awesome ";
        test3(test);
        return 10;
    }
    
    
    function test3(string storage str) private  {
        str = " changed ";
    }

¿Por qué la llamada test2da como resultado:

TypeError: el tipo literal_string "cambiado" no se puede convertir implícitamente al puntero de almacenamiento de cadena de tipo esperado. str = " cambiado "; ^---------^

Respuestas (1)

Cuando declara un parámetro como almacenamiento, está limitando la función para aceptar solo parámetros con ese calificador.

Los calificadores storagey especifican dónde se encuentran los datos memory. calldataPuede convertir implícitamente storagea memoryy calldataa memory, pero lo contrario no es posible.

string public stor = "banana";

function test(string calldata calld) external view {
    string memory memo = "pizza";

    foo(memo, stor);
    foo(calld, stor);  // Creates a copy of calld in memory and passes as parameter
    foo(stor, stor);   // Creates a copy of stor in memory and passes as parameter
    
    foo(memo, stor);
    // foo(memo, memo); // Cannot convert from memory to storage
    // foo(memo, calld); // Cannot convert from calldata to storage
}

function foo(string memory, string storage) internal view {
    
}

/* This fails because you can only use calldata on external functions
function bar(string calldata) internal view {
    
} */

Los tipos de valor como bool, uintXXX, bytesYY, dirección, etc. se pasan por valor. Los tipos sin valor como estructuras, matrices, cadenas se pasan por referencia.

  • Las funciones que son publicy pueden usar tipos pasados ​​por referencia, pero solo si se llaman desde el mismo contrato internal.private

  • Funciona publicy externalrecibirá una copia cuando lo llame un usuario habitual de otro contrato.

No sé por qué, pero al menos desde solc 0.3 no estaba permitido.

la respuesta a la segunda pregunta. usted dice: Las funciones que son públicas, internas y privadas pueden usar tipos pasados ​​por referencia, pero solo si se llaman desde el mismo contrato. Aún así, si tiene una palabra clave de almacenamiento en el parámetro para la función pública, el compilador grita y no le permite hacerlo.
Además, el compilador pide esto a gritos: prueba de función (string calldata calld) vista externa {, la ubicación de calldata no está permitida aquí
@NikaKurashvili Solc se equivoca al usar el almacenamiento como calificador en la función pública como dijiste, pero funciona con el calificador de memoria. Estoy probando con solc 0.6.6 y 0.7.2 y ambos aceptan function test(string calldata calld) external viewsin previo aviso.