探索
连接社区,发现新想法。
社区
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
热门帖子顶尖成员- 458
- 426
- 409
Move is an executable bytecode language used to implement custom transactions and smart contracts.
热门帖子顶尖成员- 271
- 260
- 251
Peera is a decentralized questions and answers protocol for Web3 where users can organize and store their interests and skills, creating a common community platform
顶尖成员- 328
- 286
- 225
The InterPlanetary File System (IPFS) is a protocol, hypermedia and file sharing peer-to-peer network for storing and sharing data in a distributed file system.
热门帖子顶尖成员- 25
- 20
- 20
Walrus is a decentralized storage and data availability protocol designed specifically for large binary files, or "blobs"
热门帖子顶尖成员- 41
- 40
- 38
赏金
- +15Xavier.eth301为SuiJun 17, 2025
能力约束如何与异构集合中的动态字段相互作用?
我正在建立一个需要处理具有不同能力要求的多种资产类型的市场,我遇到了一些关于Move类型系统的基本问题. 我想将不同的资产类型存储在同一个集合中,但它们有不同的能力: -常规 NFT:key + store(可转让) -Soulbound 代币:key 仅限(不可转让) -具有转移限制的自定义资产 public struct Marketplace has key { id: UID, listings: Bag, // Want to store different asset types here } // This works for transferable assets public fun list_transferable( marketplace: &mut Marketplace, asset: T, price: u64 ) { /* ... */ } // But how to handle soulbound assets? public fun list_soulbound( // No store ability marketplace: &mut Marketplace, asset_ref: &T, // Can only take reference price: u64 ) { /* How do I store metadata about this? */ } 关键问题: -能力要求:使用时dynamic_field::add(),Vstore 编译时是否总是需要的?包装器类型能解决这个问题吗? -异构存储:单个 Bag 能否存储具有不同能力集(key + store + copyvskey + store)的对象,并在运行时以不同的方式处理它们? -类型安全:由于动态字段会执行类型擦除,因此在检索值时如何保持类型安全?存储类型元数据的模式是什么? -见证模式:能力限制如何与幻影类型一起使用?我可以将Asset和存储Asset在同一个集合中并稍后提取类型信息吗? 建立一个系统,在该系统中,NFT、soulbound 代币和受限资产都需要市场功能,但转移语义不同. 我尝试过包装器类型,每个能力集合有多个集合,单独的类型元数据存储. 每种方法都在类型安全性、燃气成本和复杂性之间进行权衡.
03 - +10为SuiMay 29, 2025
当 Move 结构有命名字段时,为什么 BCS 需要精确的字段顺序才能进行反序列化?
当 Move 结构有命名字段时,为什么 BCS 需要精确的字段顺序才能进行反序列化? 我一直在深入研究 Move 中的 BCS 编码/解码,特别是跨链通信和链下数据处理. 在浏览 Sui Move 文档中的示例时,我遇到了一些似乎违反直觉的行为,我正在尝试理解底层的设计决策. 根据BCS规范,“BCS中没有结构(因为没有类型);该结构只是定义了字段序列化的顺序. ”这意味着在反序列化时,我们必须按照与peel_*结构字段定义完全相同的顺序使用函数. 我的具体问题: 设计理由:当 Move 结构具有命名字段时,为什么 BCS 需要精确的字段顺序匹配?像 JSON 或其他自描述格式一样,将字段名称与值一起序列化不是更强大吗? 泛型类型交互:文档提到 “包含泛型类型字段的类型最多可以解析到第一个泛型类型字段. ”考虑一下这个结构: struct ComplexObject has drop, copy { id: ID, owner: address, metadata: Metadata, generic_data: T, more_metadata: String, another_generic: U } 部分反序列化在这里到底是如何工作的?我可以反序列化到more_metadata并忽略两个泛型字段,还是第一个泛型字段(generic_data)完全阻止了进一步的反序列化? 跨语言一致性:使用 @mysten /bcs JavaScript 库序列化将由 Move 合约使用的数据时,在以下情况下会发生什么: -我不小心重新排序了 JavaScript 对象中的字段? -Move 结构定义会在合约升级中更改字段顺序? -我有带有自己的泛型参数的嵌套结构吗? 实际启示:在生产系统中,团队如何处理 BCS 架构演变?您是否对BCS架构进行了版本控制,还是期望结构字段顺序在部署后不可变?
53 - +10为MoveMar 11, 2025
Sui Move vs Aptos Move - What is the difference?
Sui Move and Aptos Move - two prominent implementations of the Move programming language. While both are rooted in the same foundational principles, they have diverged significantly in design, execution, and ecosystem development. To better understand their differences, we need to uncover some of their key aspects: How do their runtimes differ? Both Sui and Aptos implement their own custom Move virtual machines (VMs). How does this impact performance, scalability, and developer experience? For instance: Does Sui's runtime optimize for parallel execution differently than Aptos'? Are there notable differences in transaction lifecycle management or gas models? What are the differences between their standard libraries? The Move standard library is a critical component for building smart contracts. However, Sui and Aptos have forked their implementations, leading to divergence: Are there modules or functions unique to one implementation but absent in the other? How do these differences affect common use cases like token creation, NFTs, or decentralized finance (DeFi)? How does data storage differ between them? One of the most significant distinctions lies in how Sui and Aptos handle data storage: Sui uses an object-centric model, where each object has its own ownership and permissions. Aptos, on the other hand, retains a more traditional account-based model similar to Ethereum. How does this impact state management, composability, and gas efficiency? Is it fair to say that Aptos is closer to EVM while Sui is closer to SVM? Some developers argue that Aptos' account-based architecture resembles Ethereum's EVM, while Sui's object-centric approach aligns more closely with Solana's SVM. Do you agree with this analogy? Why or why not? How does this architectural choice influence developer ergonomics and application design? Are there universal packages working for both Sui Move and Aptos Move? Given their shared origins, it would be ideal if some libraries or tools were interoperable across both ecosystems. Are there any existing universal packages or frameworks that work seamlessly on both platforms? If not, what are the main barriers to achieving compatibility? Can one of them be transpiled into another? If a project is built on Sui Move, could it theoretically be transpiled to run on Aptos Move, or vice versa? What are the technical challenges involved in such a process? Are there tools or compilers currently available to facilitate this kind of migration?
21
最新的
How to fix 'Cannot open wallet config file' error in Walrus?
I'm trying to use the Walrus CLI to store a file with the command walrus store --wallet. However, I'm encountering an error: Cannot open wallet config file at "~/.sui/sui_config/client.yaml". Err: Unable to load config. I've tried using relative and absolute paths in the command, but the error persists. I can open the file using a text editor, so I know it exists. How can I resolve this issue?
04- 为SuiJun 19, 2025
Soulbound 可转让资产
很棒的文章!我想补充一些实用观点,以加强Sui Move中异构资产的设计和类型安全性: ✅ 由于dynamic_field::add()需要该store能力,因此key无法直接存储诸如soulbound代币(仅有)之类的资产. ID取而代之的是,只存储 store确实拥有的和清单的元数据. ✅ 最佳方法:根据能力约束将馆藏分开: -VecMap→ 适用于key + store资产(例如,可转让的 NFT) -VecMap→ key仅限资产(例如 soulbound 代币) ✅ asset_type: String向元数据添加运行时标签. 这使您能够识别和安全地处理资产逻辑(例如转移、显示),即使在删除了类型后也是如此. ✅ Phantom 类型非常适合编译时类型标记和防止开发者滥用(例如意外转移不可转让的代币). 这种模块化结构具有可扩展性,可避免违反移动能力的行为,并允许在不牺牲安全性的情况下进行灵活的市场设计. 解释得这么透彻真是太棒了!
01
未回答
结构发生变化时如何更新商家在ObjectTable中的密钥?
大家好,我才刚刚开始写智能合约,我正在做我的第一个项目. 对于我遇到的问题,我很乐意得到一些帮助. 到目前为止,我已经创建了一个Merchant看起来像这样的结构: -id:唯一标识符 (UID) -owner: 商家的地址 -key: 用作唯一密钥的字符串 -balance: 一个 u64 代表他们的余额 我还做了一个MerchantRegistry结构来管理所有商家: -id: 另一个 UID -merchant_to_address:将ObjectTable地址映射到商家 -merchant_to_key:将密ObjectTable钥映射到商家 我希望能够通过卖家的地址或他们的密钥来查找他们. 当用户更新Merchant结构内的密钥时,更改不会自动更新merchant_to_key表中的密钥. 这意味着旧钥匙仍然指向商家,这会破坏事情. 我尝试从表中删除该条目并使用新密钥将其插回去,但我一直遇到错误,例如: “没有掉落能力就无法忽略数值” 我很确定这是一个初学者的错误,但我无法在任何地方找到明确的解释或解决方案. 有没有正确的方法来处理结构和查找表中的密钥更新?
20
趋势
- 0xduckmove409为SuiApr 08, 2025
👀 SEAL-我认为 Web3 数据隐私即将改变
👀 SEAL 已在 Sui 测试网上线 — 我认为 Web3 数据隐私即将改变 在 Web3 中,经常会听到诸如“用户拥有自己的数据”或“通过设计去中心化”之类的短语. 但是,仔细观察,许多应用程序仍然依赖集中式基础设施来处理敏感数据——使用 AWS 或 Google Cloud 等服务进行密钥管理. 这就引入了一个矛盾:表面上的去中心化,底层的集中化. 但是,如果有一种方法可以在不放弃权力下放的情况下安全地管理机密呢?介绍 SEAL — 去中心化机密管理 (DSM),现已在 Sui 测试网上线. SEAL 旨在修复 Web3 最大的虚伪之处之一:在秘密使用 AWS 的同时大声疾呼去中心化 你可能会问我:海豹突击队是什么? SEAL 是一种协议,可让您安全、分散地管理敏感数据——专为 Web3 世界构建. 可以将其视为插入 dApp 的隐私优先访问控制层. 您可以将 SEAL 视为一种可编程的数据锁. 你不只是手动锁定和解锁,而是使用Move on Sui将策略直接写入智能合约. 假设你正在构建一个 DApp,其中: -只有 NFT 持有者才能解锁高级教程 -或者,在泄露敏感文件之前,DAO 可能必须进行投票 -或者你想对元数据进行时间锁定并且只能在特定日期之后访问 海豹突击队使所有这些成为可能. 访问控制在链上 运行,完全自动化,无需管理员进行管理. 只是逻辑,直接融入区块链. 海豹突击队使所有这些成为可能. 访问控制在链上 运行,完全自动化,无需管理员进行管理. 只是逻辑,直接融入区块链. 另一个有趣的文章是SEAL如何处理加密. 它使用所谓的阈值加密,这意味着:没有一个节点可以解密数据. 需要一组服务器才能协同工作——有点像多重签名,但用于解锁机密. 这样可以分配信任,避免常见的单点故障问题. 为了保证信息的真正私密性,SEAL 会加密和解密客户端的所有内容. 任何后端都看不到您的数据. 从字面上看,它会留在你的手中,放在你的设备上. 而且 SEAL 不在乎你在哪里存储数据. 无论是 IPFS、Arweave、Walrus 还是其他平台,SEAL 都不会试图控制这部分. 它只关注谁可以看到什么,而不是东西的存储位置. 所以是的,它不仅仅是一个库或 API,它是 dApp 的链上优先、访问控制、默认隐私层. SEAL 填补了一个非常关键的空白. 让我们再分解一下. 如果你正在构建一个处理任何形式的敏感数据(封闭内容、用户文档、加密消息,甚至是锁定时间的 NFT 元数据)的 dApp,你也会遇到同样的问题: ➡️ 如何在不依赖集中服务的情况下安全地管理访问权限? 如果没有像海豹突击队这样的队伍,大多数队伍都会: 使用 AWS KMS 或 Firebase 等集中式工具,这显然与去中心化背道而驰 或者尝试自己修补半生不熟的加密逻辑,这些逻辑通常会变得脆弱且难以审计 https://x.com/EmanAbio/status/1908240279720841425?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1908240279720841425%7Ctwgr%5E697f93dc65359d0c8c7d64ddede66c0c4adeadf1%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fwww.notion.so%2Fharryph%2FSEAL-Launches-on-Sui-Testnet-1cc4f8e09bb380969c0dcc627b96cc22 这两个比例都不好. 尤其是在你尝试跨多个链或社区构建无需信任的应用程序时. *SEAL 使整个过程模块化和可编程. * 您可以在Move智能合约中定义访问规则,SEAL会处理其余的——密钥生成、解密批准和访问强制执行——所有这些都无需任何人手动颁发密钥或进行后端检查. 更好的是,这些规则是可审计和不可改变的——一旦上链,它们就会遵循合同,而不是人工管理员. 因此,与其问 “谁应该管理对这些数据的访问权限?”你只要问: “应该用什么逻辑来定义访问权限?” >... 然后让链条来处理. 简洁且可扩展. 这就是SEAL不仅仅涉及 “安全工具” 的原因——它是*任何关心隐私、合规性或动态访问逻辑的DApp的基础层. * 这是一个很小的转变——但它改变了我们对 Web3 中数据的看法. *与其在部署后进行加密,或依赖外部服务,不如从内置隐私开始——访问权限完全由智能合约逻辑处理. * 而这正是 Web3 现在需要的. SEAL 实际上是如何运作的? 我们已经介绍了什么是 SEAL以及为什么 Web3 需要它,让我们来看看它在幕后是如何构建的. 这部分是技术性更强的地方,但还是不错的. 一旦你看到所有部分是如何组合在一起的,建筑就会变得很优雅. 总体而言,SEAL的工作原理是使用一种名为基于身份的加密(IBE)的技术,将链上访问逻辑与链下密钥管理相结合. 这允许开发人员将数据加密为身份,然后依靠智能合约来定义允许谁对其进行解密. 步骤 1:智能合约中的访问规则(在 Sui 上) 一切都从智能合约开始. 当你使用 SEAL 时,你需要在你的 Move 合约中定义一个名为 seal_approve 的函数,你可以在这里写下解密条件. 例如,以下是用 Move 编写的简单时间锁定规则: entry fun seal_approve(id: vector, c: &clock::Clock) { let mut prepared: BCS = bcs::new(id); let t = prepared.peel_u64(); let leftovers = prepared.into_remainder_bytes(); assert!((leftovers.length() == 0) && (c.timestamp_ms() >= t), ENoAccess); } 一旦部署,该合约将充当看门人. 每当有人想要解密数据时,他们的请求都会被根据这个逻辑进行检查. 如果通过,密钥将被释放. 如果没有,他们就会被封锁. 没有人需要干预. ##步骤 2:基于身份的加密 (IBE) 这就是魔法发生的地方. SEAL 没有加密特定钱包地址(如 PGP 或 RSA)的数据,而是使用身份字符串——这意味着你可以加密成类似的内容: -0x 钱包地址 -dao_voted: proposal_xyz -pkgid_2025_05_01(基于时间戳的规则) -甚至是 game_user_nft_holder 当数据加密后,它看起来像这样: Encrypt(mpk, identity, message) -mpk = 主公钥(众所周知) -身份 = 逻辑定义的收件人 -消息 = 实际数据 之后,如果有人想解密,密钥服务器会检查他们是否符合政策(通过链上的 seal_approve 调用). 如果获得批准,它将返回该身份的派生私钥. Derive(msk, identity) → sk Decrypt(sk, encrypted_data) 然后,用户可以在本地解密内容. 因此,无需提前知道谁将解密即可完成加密. 您只需定义条件,SEAL 稍后再计算其余部分. 它是动态的. ##第 3 步:密钥服务器 — 脱链,但未集中化 你可能想知道:谁在拿着这些万能钥匙? 这就是 SEAL 的密钥服务器的用武之地. 可以把它看作是一个后端: -持有主密钥 (msk) -关注链上合约(比如你的 seal_approve 逻辑) -仅在满足条件时才发出派生密钥 但是——这是关键——海豹突击队不只依赖一台密钥服务器. 你可以在阈值模式下运行它,在发放解密密钥之前,需要多个独立服务器达成一致. 例如:五分之三的密钥服务器必须批准请求. 这避免了中心故障点,也允许在密钥管理层进行权力下放. 更好的是,将来SEAL将支持MPC(多方计算)和基于飞地的设置(例如TEE),因此您可以在不影响可用性的情况下获得更强的保障. ##步骤 4:客户端解密 将密钥返回给用户后,实际的解密将在用户的设备上进行**. 这意味着: -服务器永远看不到你的数据 -后端从不存储解密的内容 -只有用户可以访问最后的消息 这是一个可靠的隐私模型. 即使有人破坏了存储层(IPFS、Arweave 等),如果不传递访问逻辑,他们仍然无法读取数据. 以下是快速思维模型: 这种结构使您可以轻松构建访问规则不是硬编码的去中心化应用程序,它们是动态的、可审计的,并且完全集成到您的链逻辑中. ##SEAL 背后的团队 SEAL 由区块链安全社区的知名人物Samczsun领导. 他曾是Paradigm的研究合伙人,曾审计过多个生态系统并将其从重大漏洞中拯救出来. 现在,他全职致力于将 SEAL 建成 Web3 隐私基础设施的核心部分. 凭借他的背景和信誉,SEAL 不仅仅是另一个实验工具,它是一次严肃的尝试,旨在使去中心化数据隐私既实用又可扩展. 随着 SEAL 在 Sui 测试网上线,它为 Web3 应用程序如何管理机密带来了新的标准. 通过结合链上访问控制、阈值加密和客户端隐私,SEAL 为去中心化数据处理提供了更值得信赖的基础. 无论你是在构建 dApp、DAO 还是去中心化游戏,SEAL 都提供了一个强大的工具包,可以在不影响去中心化的前提下执行访问控制和保护用户数据. 如果 Web3 要向前发展,像 SEAL 这样的安全基础设施不是可选的——这是必不可少的
8 Sui 生态系统中的 AMM 机器人
Sui 生态系统中 AMM 机器人的主要特征和功能是什么?他们如何改进传统的交易机制,以及它们为在Sui网络上使用DeFi协议的用户提供了哪些优势? 例如,我需要建造一个还是可以使用 Turbos Finance
62- harry phan458为SuiApr 24, 2025
使用 public_receive 进行跨模块儿童管理
这是 “Sui Move 中的亲子对象” 系列的第 3 部分. 有时,您的父类型和子类型是在不同的模块甚至不同的包中定义的. 例如,您可能有一个可以存储任何类型的 Parcel 对象的通用仓库对象. 仓库模块想要提取一个包裹子节点,但是包裹类型是在其他地方定义的. 在这种情况下,我们使用 transfer:: public_receive,它是 receive 的跨模块表兄弟. ###接收 vs public_receive 正如我们所见,transfer:: receive 只能在定义 T(或朋友)的模块中调用,因为它不需要 T: store. Move 字节码验证器实际上确保在任何要接收的调用中,T 类型来自当前模块. 这是对仅限钥匙的对象的安全限制. transfer:: public_receive 是一个变体,它需要 T: key + store,但允许在 T 的模块之外接收. 换句话说,如果对象类型具有存储能力(这意味着它可以自由存在于全局存储中),则任何模块(给定父模块的 &mut UID)都可以使用 public_receive 接收它. 这非常适合父模块与子模块不同的情况. 为什么需要商店?因为存储标志着该对象可以安全地保存并在其定义模块之外传递. 仅限密钥的对象可能具有原始模块希望在传输/接收时强制执行的自定义不变量;通过排除public_receive中的那些不变量,Sui会强制开发人员在模块内处理它们(正如我们将在灵魂绑定对象中看到的那样). 如果一个对象有存储,则更宽松,而且 Sui 允许使用通用的传输/接收逻辑在外部对其进行管理. ###示例:分离父模块和子模块 让我们用一个简单的场景来说明一下:一个存储 Parcel 对象的仓库. 包裹类型在自己的模块中定义,仓库在另一个模块中定义. 我们将展示仓库如何使用 public_receive 接收子包裹. module demo::parcel { // Child module use sui::object::{Self, UID}; use sui::tx_context::{Self, TxContext}; /// A parcel object that can be stored in a Warehouse. /// It has both key and store, so it can be transferred across modules. struct Parcel has key, store { id: UID, contents: vector } public entry fun create_parcel(contents: vector, ctx: &mut TxContext): Parcel { Parcel { id: object::new(ctx), contents } } } module demo::warehouse { // Parent module use sui::transfer::{Self, Receiving, public_receive}; use demo::parcel::{Self, Parcel}; use sui::object::{UID}; use sui::tx_context::{Self, TxContext}; struct Warehouse has key { id: UID, location: address } public entry fun create_warehouse(location: address, ctx: &mut TxContext): Warehouse { Warehouse { id: object::new(ctx), location } } /// Receive a Parcel that was sent to this Warehouse. /// Returns the Parcel to the caller (transferred to caller's address). public entry fun withdraw_parcel( warehouse: &mut Warehouse, parcel_ticket: Receiving, ctx: &mut TxContext ): Parcel { // Using public_receive because Parcel is defined in another module and has store let parcel = public_receive(&mut warehouse.id, parcel_ticket) oai_citation_attribution:27‡docs.sui.io oai_citation_attribution:28‡github.com; // Transfer the parcel to the transaction sender (so the caller gets ownership) transfer::transfer(parcel, tx_context::sender(ctx)); // We return nothing because we've transferred the Parcel out to the caller. } } 让我们分解一下 redath_parcel 中发生了什么: -我们打电话给 public_receive (&mut warehouse.id, parcel_ticket)由于 Parcel 具有存储能力,因此即使我们不在包裹模块中,也允许此调用. 在幕后,它会执行与接收相同的检查和提取,但允许跨模块进行检查,因为存储表明这样做是安全的. https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/transfer.move#:~:text=public%20fun%20public_receive,T%3E%29%3A%20T -然后,我们会立即将收到的包裹转到来电者的地址(tx_context:: sender(ctx)). 此步骤可确保包裹离开仓库并交给发起提款的用户. 我们也可以直接从函数中返回 Parcel,然后 Sui 会将其视为由调用者地址拥有的输出(因为它是输入函数的输出). 进行显式传输更为冗长,但可以清楚地说明发生了什么(并允许我们在释放对象之前进行任何检查). 为什么要在包裹中加入店铺?如果 Parcel 缺乏存储能力(即只有密钥),则 demo:: warehouse 中的 public_receive 调用将无法编译 — Sui 强制要求 T 为 public_receive 存储. 在这种情况下,我们将被迫在包裹模块本身中使用接收功能(或使用某种朋友关系)来取回包裹,这会使跨模块的设计变得复杂. 通过在 Parcel 中添加存储,我们实际上是在说 “这个对象可以自由移动和被外部模块接收”,这正是我们想要的通用容器模式. 函数调用模式:要在交易中使用它们,流程为: 存款(转移到对象):致电转移:: public_transfer(parcel_obj,@warehouse_id)将包裹发送到仓库. 这会将包裹的所有者标记为仓库. (我们在这里使用 public_transfer 是因为它在 Parcel 模块之外,而且 Parcel 有存储. 在包裹模块内,普通的传输也可以. ) 提款(收回):稍后,致电撤回包裹(warehouse_obj,接收(包裹编号,...)). SDK 可以通过引用包裹的 ID 和最新版本来获取接收信息. 该函数将调用 public_receive 然后将包裹转移给你. 在拨打 redth_parcel 电话后,包裹的所有者回到了一个地址(你的),所以它又是一个普通的地址拥有的物品. 仓库不再拥有它. 跨模块注意事项:请注意,仓库模块需要了解包裹类型(我们使用 demo:: parcel:: Parcel). 这是因为我们将接收明确键入为接收. 如果你想要一个可以接收任何类型对象的真正通用容器,你必须使用泛型或其他方法(可能是带有类型擦除的动态字段). 但是对于大多数用例,你会知道你期望的是什么类型的孩子. 为什么 public_receive 而不只是调用 receive?如果我们尝试在仓库模块中转移:: 接收(&mut warehouse.id,parcel_ticket),则移动验证器会拒绝,因为在 demo:: warehouse 中没有定义包裹. Sui 提供了 public_receive 作为通过额外能力检查(需要存储)来实现此目的的好方法. 同样,Sui 也有传输与 public_transfer、freeze_object 与 public_freeze_object 等,遵循相同的模式:public_ 版本在定义模块之外使用,需要存储. 别忘了家长的许可:即使有 public_receive,你仍然需要那个 &mut warehouse.id. 我们之所以得到它,是因为撤回包裹在 Warehouse 的模块中并接受 &mut Warehouse. 因此,只有可以这样称呼的人(仓库的所有者)才能提取包裹. 如果仓库模块没有公开提供这样的函数,那么也没有人可以在外部对其子模块调用 public_receive. 因此,跨模块不会绕过父级的控制;它只允许父级的代码处理其未定义类型的子类型. 关于存储能力的说明:提供对象存储可以使其更加灵活,但限制稍微减少一点——任何具有父引用的模块都可以使用 public_receive 将其拉出. 如果你想限制对象的检索方式(例如,强制执行自定义逻辑或防止轻松提取),你可以故意将其设为仅限密钥. 我们将用灵魂束缚的物体来看这个例子. 在这种情况下,你可以实现自定义接收函数,而不是依赖 public_receive. 总结一下这部分:public_receive 是你管理其他模块中定义的子对象的好友,只要这些对象具有存储能力即可. 它允许您构建跨模块系统(例如我们的仓库/包裹),同时仍然尊重所有权和访问控制. 只要记得在子类型上添加存储,并在从模块外部将它们发送给父类型时使用 public_transfer 即可.
5