首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >内有映射的嵌套结构

内有映射的嵌套结构
EN

Ethereum用户
提问于 2020-05-22 09:57:18
回答 1查看 3.4K关注 0票数 1

我有以下代码:

代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.7.0;
pragma experimental ABIEncoderV2; 

contract VenueRegistry{
    struct Queue{
        uint head;
        uint tail;
        mapping(uint => address) queue;
    }

    struct Venue{
        uint id;
        Queue queue;
    }

    mapping (uint => Venue) public venues;

}

我得到以下错误:

TypeError:公共状态变量不允许内部或递归类型。测绘(uint =>场馆)公共场所;

因此,我把venues变成了私有的,并写了一个getter:

代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.7.0;
pragma experimental ABIEncoderV2; 

contract VenueRegistry{
    struct Queue{
        uint head;
        uint tail;
        mapping(uint => address) queue;
    }

    struct Venue{
        uint id;
        Queue queue;
    }

    mapping (uint => Venue) venues;

    function getVenue(uint _index) public view returns(Venue memory){
        return venues[_index];
    }
}

然后,我得到以下错误:

只允许库在公共或外部函数中使用映射类型。

问题似乎在于struct Queue内部的映射。当我删除映射时,它就能工作了。是否有一种方法可以让嵌套的结构中包含映射?

EN

回答 1

Ethereum用户

回答已采纳

发布于 2020-05-22 16:17:05

问题是您在两个地方使用了不兼容数据结构的public

首先,这一行:

pragma solidity >=0.4.22 <0.7.0;

这使得无法复制您的结果,因为没有人知道您正在使用的编译器。出于这个原因,在主合同中具体说明,强制执行某个版本是很好的。如果继承的合同、库等具有更大的灵活性,这是可以的,因为主契约仍然会强制解决这个问题。

我用了Solc 6.6。

在第16行:

public对状态变量做了几件事。如果你想要所有的东西,这是非常方便的,但是如果你不想要所有的东西,你可以手动编码。其中之一是一个看起来像function variable(args) public returns(...的“免费”getter。

它适用于标量变量、数组和映射,因此uint public x;是not的,uint[] public x;是可以的,但是myComplexStructWithMoreIndexedStuff[] public x;是不兼容的。总之,这是因为编译器不确定如何为您构造getter。

没问题。只需将其设置为私有或内部,并编写自己的getter函数以请求参数、获取元素并返回响应。

所以:

mapping (uint => Venue) private venues;

在第18行:

同样,public和您试图返回一个包含内部映射的结构。一个结构本身就足以导致与public一起出现的问题。

对于结构、数组和映射,函数参数是存储指针,意味着对存储位置的32字节引用,而不是实际数据。对于契约本身信任的内部和私有上下文来说,这是很好的。但是,存储指针不能传入或输出。

请注意,系统不会对数据进行迭代以产生关于变量值的冗长响应,而且可能永远不会,因为这将导致O(n)复杂性--链上的高CPU和I/O活动,而这是您不想要的。由于它不能返回数组的所有元素,也不能返回指向存储的简单指针,所以它无能为力。

可以重写它以返回一个元素,以及该元素的任何内容,如下所示:

代码语言:javascript
复制
function getVenueQueueElement(uint id, uint row) public view returns(address) {
  return venues[id].queue[row];
}

您可以考虑一种更好的数据结构,以便于枚举存在的场所和队列成员,这样客户端就不应该请求无稽之谈和契约对象。

看看这个更新的解释器,一定要阅读第1和第2部分,以真正理解正在发生的事情和解决的问题:https://medium.com/robhitchens/solidity-crud-epilogue-e563e794fde

它在内部使用存储指针。它们是神秘的东西,所以这可能会有帮助:https://blog.b9lab.com/storage-pointers-in-solidity-7dcfaa536089

希望能帮上忙。

票数 2
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/83625

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档