Solidity - почему метод получения по умолчанию общедоступной переменной Struct не возвращает каждую переменную внутри Struct
В настоящее время я изучаю язык Solidity и заметил, что когда я пытаюсь получить значение Struct внутри своего JS-кода, Solidity возвращает каждую переменную без массивов. Мне нужно создать собственный получатель для доступа ко всем данным внутри моей структуры.
Я сделал очень простой пример контракта со структурой, инициализированной внутри конструктора.
Я обращаюсь к переменной с помощью своего пользовательского получателя и сгенерировал ее внутри JS-кода.
Test.sol
pragma solidity ^0.8.4;
contract Test {
struct Data {
string foo;
address[] bar;
address ctrt;
}
Data public d;
constructor() {
d.foo = "HELLO WORLD";
d.bar.push(msg.sender);
d.ctrt = address(this);
}
function getD() public view returns (Data memory) {
return d;
}
}
Test.js
const {ethers} = require('hardhat');
describe('Test', function () {
it('should test something', async function() {
const factory = await ethers.getContractFactory('Test')
const test = await factory.deploy();
console.log("Result from var:");
console.log(await test.d());
console.log("Result from getter:");
console.log(await test.getD());
})
});
Результат в консоли:
Result from var:
[
'HELLO WORLD',
'0x5FbDB2315678afecb367f032d93F642f64180aa3',
foo: 'HELLO WORLD',
ctrt: '0x5FbDB2315678afecb367f032d93F642f64180aa3'
]
Result from getter:
[
'HELLO WORLD',
[ '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' ],
'0x5FbDB2315678afecb367f032d93F642f64180aa3',
foo: 'HELLO WORLD',
bar: [ '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' ],
ctrt: '0x5FbDB2315678afecb367f032d93F642f64180aa3'
]
Какой смысл явно говорить, что переменная является общедоступной, если какая-то часть данных не видна?
2 ответа
Автоматические геттеры, созданные для структур, возвращают все элементы структуры, кроме элементов, являющихся отображениями и массивами. Документы Solidity объясняют:
Сопоставление и массивы (за исключением массивов байтов) в структуре опущены, поскольку нет хорошего способа выбрать отдельные элементы структуры или указать ключ для сопоставления.
Итак, для вашего примера автоматически сгенерированный геттер выглядит так:
function d() public returns (string foo, address ctrt) {
foo = d.foo;
ctrt = d.ctrt;
}
И, как и ожидалось, в вашем примере автоматически сгенерированный метод получения возвращает все элементы структуры, которые не являются отображениями или массивами, а ваш метод получения возвращает все элементы.
Цитата документов:
Если у вас есть общедоступная переменная состояния типа массива, вы можете получить только отдельные элементы массива с помощью сгенерированной функции получения. Этот механизм существует, чтобы избежать высоких затрат на газ при возврате всего массива.
Вот почему, когда вы выполняете вызов с помощью ethers.js, вы не видите этого значения.
Решение - создать
getDataBar(uint i)
функция, возвращающая содержимое бара.