You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mojo中如何加载内存仅存类型指针?图结构实现遇阻

Mojo实现图结构时Pointer.load()报错的解决方法

问题描述

手动实现图结构的Node和NodeEdge结构体,NodeEdge通过Pointer[Node]存储关联节点的指针,但在printFirstEdgeNode函数中调用pointer.load()加载Node对象时触发错误,需要找到可行的实现方式完成关联节点的打印需求。

原代码

from memory import Pointer
from collections import List

struct NodeEdge:
    var node1P: Pointer[Node] 
    var node2P: Pointer[Node]
    var edgeWeight: UInt16 

    fn __init__(inout self, inout node1: Node, inout node2: Node, weight: UInt16) -> NoneType:
        self.node1P = Pointer[Node].address_of(node1)
        self.node2P = Pointer[Node].address_of(node2)
        self.edgeWeight = weight
        node1.addEdge(self)
        node2.addEdge(self)

    fn __copyinit__(inout self, node1: NodeEdge) -> NoneType:
        self.node1P = node1.node1P
        self.node2P = node1.node2P
        self.edgeWeight = node1.edgeWeight

    fn __moveinit__(inout self, owned node1: NodeEdge) -> NoneType:
        self.node1P = node1.node1P
        self.node2P = node1.node2P
        self.edgeWeight = node1.edgeWeight


struct Node:
    var nodeType: String
    var nodeData: List[UInt16]
    var nodeEdges: List[NodeEdge]

    fn __init__(inout self) -> NoneType:
        self.nodeType = ''
        self.nodeData = List[UInt16]()
        self.nodeEdges = List[NodeEdge]()
        

    fn __init__(inout self, ntype: String, data: List[UInt16], edges: List[NodeEdge]) -> NoneType:
        self.nodeType = ntype
        self.nodeData = data
        self.nodeEdges = edges

    fn addEdge(inout self, edge: NodeEdge) -> NoneType:
        self.nodeEdges.append(edge)

    fn setNodeType(inout self, ntype: String) -> NoneType:
        self.nodeType = ntype

    fn setNodeData(inout self, data: List[UInt16]) -> NoneType:
        self.nodeData = data

    fn setNodeEdgeData(inout self, data: List[NodeEdge]) -> NoneType:
        self.nodeEdges = data

    fn printNode(inout self) -> String:
        var res: String
        res = self.nodeType + "\n"
        for i in range(self.nodeData.size):
            res.__iadd__(self.nodeData[i])
            res.__iadd__(" ")
        res.__iadd__("\n")

        for i in range(self.nodeEdges.size):
            res.__iadd__(self.nodeEdges[i].edgeWeight)
            res.__iadd__(" ")
        res.__iadd__("\n")
        return res

    fn printFirstEdgeNode(inout self) -> String:
        var res: String
        var firstNodeEdge = self.nodeEdges[0]
        var pSelf = Pointer[Node].address_of(self)
        if (pSelf.__eq__(firstNodeEdge.node1P)):
            # 错误发生在这里
            var nodeToPrint = firstNodeEdge.node2P.load()
        else: 
            # 打印另一个节点
            pass
        return ''



fn main():
    var node1 = Node()
    var ndata1: List[UInt16]
    
    var node2 = Node()
    var ndata2: List[UInt16]

    ndata1 = List[UInt16](17)
    ndata2 = List[UInt16](12,2)
    node1.setNodeType("Sum")
    node2.setNodeType("Path")
    node1.setNodeData(ndata1)
    node2.setNodeData(ndata2)

    createEdges(node1, node2)
    print(node1.printFirstEdgeNode())


fn createEdges(inout node1: Node, inout node2: Node) -> NoneType:
    var edge = NodeEdge(node1, node2, 5)

错误原因

  1. 内存生命周期问题:代码中的Node是栈分配的局部变量,当NodeEdge被复制到Node的nodeEdges列表中时,原指针指向的栈对象可能因作用域结束而销毁,或者指针指向的内存地址不再有效。
  2. Mojo的安全限制:Pointer.load()要求指针指向的对象必须是堆分配且拥有稳定的内存地址,栈分配的结构体不满足此要求,直接加载会触发内存安全错误。

可行解决方案

方案1:使用堆分配的Node(Box包裹)

将Node用Box包裹,确保内存地址稳定,修改后的核心代码如下:

from memory import Pointer
from collections import List
from pointers import Box

struct NodeEdge:
    var node1P: Pointer[Box[Node]] 
    var node2P: Pointer[Box[Node]]
    var edgeWeight: UInt16 

    fn __init__(inout self, inout node1: Box[Node], inout node2: Box[Node], weight: UInt16) -> NoneType:
        self.node1P = Pointer[Box[Node]].address_of(node1)
        self.node2P = Pointer[Box[Node]].address_of(node2)
        self.edgeWeight = weight
        node1[].addEdge(self)
        node2[].addEdge(self)

    # 复制、移动构造函数保持不变...


struct Node:
    # 结构体内容保持不变,仅修改printFirstEdgeNode:
    fn printFirstEdgeNode(inout self) -> String:
        var res: String
        var firstNodeEdge = self.nodeEdges[0]
        var nodeBox = firstNodeEdge.node2P.load()
        var nodeToPrint = nodeBox[]
        res = nodeToPrint.nodeType + " "
        for num in nodeToPrint.nodeData:
            res.__iadd__(num)
            res.__iadd__(" ")
        return res


fn main():
    var node1 = Box[Node]()
    var ndata1: List[UInt16]
    
    var node2 = Box[Node]()
    var ndata2: List[UInt16]

    ndata1 = List[UInt16](17)
    ndata2 = List[UInt16](12,2)
    node1[].setNodeType("Sum")
    node2[].setNodeType("Path")
    node1[].setNodeData(ndata1)
    node2[].setNodeData(ndata2)

    createEdges(node1, node2)
    print(node1[].printFirstEdgeNode())


fn createEdges(inout node1: Box[Node], inout node2: Box[Node]) -> NoneType:
    var edge = NodeEdge(node1, node2, 5)

方案2:用ID索引代替指针

给每个Node分配唯一ID,用容器管理所有节点,NodeEdge存储节点ID,避免指针问题:

from collections import List, Dict

struct NodeEdge:
    var node1Id: UInt64
    var node2Id: UInt64
    var edgeWeight: UInt16 

    fn __init__(inout self, node1Id: UInt64, node2Id: UInt64, weight: UInt16) -> NoneType:
        self.node1Id = node1Id
        self.node2Id = node2Id
        self.edgeWeight = weight


struct Node:
    var nodeId: UInt64
    var nodeType: String
    var nodeData: List[UInt16]
    var nodeEdges: List[NodeEdge]

    fn __init__(inout self, nodeId: UInt64) -> NoneType:
        self.nodeId = nodeId
        self.nodeType = ''
        self.nodeData = List[UInt16]()
        self.nodeEdges = List[NodeEdge]()

    # 其他方法保持不变,修改printFirstEdgeNode:
    fn printFirstEdgeNode(inout self, allNodes: Dict[UInt64, Node]) -> String:
        var res: String
        var firstEdge = self.nodeEdges[0]
        var targetId = if firstEdge.node1Id == self.nodeId: firstEdge.node2Id else firstEdge.node1Id
        var targetNode = allNodes[targetId]
        res = targetNode.nodeType + "\n"
        for num in targetNode.nodeData:
            res.__iadd__(num)
            res.__iadd__(" ")
        return res


fn main():
    var allNodes = Dict[UInt64, Node]()
    var node1 = Node(1)
    var ndata1 = List[UInt16](17)
    node1.setNodeType("Sum")
    node1.setNodeData(ndata1)
    allNodes[1] = node1

    var node2 = Node(2)
    var ndata2 = List[UInt16](12,2)
    node2.setNodeType("Path")
    node2.setNodeData(ndata2)
    allNodes[2] = node2

    var edge = NodeEdge(1, 2, 5)
    allNodes[1].addEdge(edge)
    allNodes[2].addEdge(edge)

    print(allNodes[1].printFirstEdgeNode(allNodes))

说明

方案1适合需要直接访问节点内存的场景,依赖堆分配保证内存稳定性;方案2更安全,通过ID索引避免指针生命周期问题,适合大多数图结构实现场景。

内容的提问来源于stack exchange,提问作者Ethan Harness

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:09:52