Pointers Nim中的价值与参考模型是什么?

Pointers Nim中的价值与参考模型是什么?,pointers,types,nim-lang,Pointers,Types,Nim Lang,注意:我不是在问指针和引用之间的区别,对于这个问题来说,这是完全无关的 有一件事我找不到明确说明——Nim使用什么模型 类似C++(在这里你有值和新< /Cord> >你创建指向数据的指针(在这种情况下,变量可以保存指针到指向……到数据的指针)?< /P> 或者像C#——您将POD类型作为值,但用户定义的对象带有引用(隐式) 我发现只有去参考是自动的,就像在围棋中一样 重新措辞。你定义了你的新类型,比如说Student(带有姓名、大学、地址)。你写道: var student ...? 使st

注意:我不是在问指针和引用之间的区别,对于这个问题来说,这是完全无关的

有一件事我找不到明确说明——Nim使用什么模型

类似C++(在这里你有值和<代码>新< /Cord> >你创建指向数据的指针(在这种情况下,变量可以保存指针到指向……到数据的指针)?< /P> 或者像C#——您将POD类型作为值,但用户定义的对象带有引用(隐式)

我发现只有去参考是自动的,就像在围棋中一样

重新措辞。你定义了你的新类型,比如说
Student
(带有姓名、大学、地址)。你写道:

var student ...?
  • 使
    student
    保存实际数据(属于
    student
    类型/类别)
  • 要使
    student
    保持指向数据的指针
  • 使学生持有指向数据指针的指针
  • 或者这些点中的一些是不可能的?

    默认情况下,模型是按值传递数据的。创建特定类型的变量时,编译器将在堆栈上为变量分配所需的空间。这是意料之中的,因为Nim编译成C,复杂类型只是结构。但像C或C++一样,你也可以有指针。有
    ptr
    关键字获取不安全指针,主要用于与C代码接口,还有
    ref
    获取垃圾收集的安全参考(两者都记录在Nim手册的章节中)

    但是,请注意,即使指定
    proc
    以按值传递变量,编译器也可以自由决定通过引用在内部传递该变量,前提是它认为它可以加快执行速度并且同时是安全的。实际上,我唯一一次使用引用是在我将Nim类型导出到C时,必须确保C和Nim都指向同一个内存。请记住,您始终可以在
    nimcache
    目录中检查生成的C代码。然后您将看到,proc中的
    var
    参数只是指向其C结构的指针

    下面是一个类型的示例,该类型的构造函数将在堆栈上创建并通过值传入,以及相应的类似指针的版本:

    type
      Person = object
        age: int
        name: string
    
    proc initPerson(age: int, name: string): Person =
      result.age = age
      result.name = name
    
    proc newPerson(age: int, name: string): ref Person =
      new(result)
      result.age = age
      result.name = name
    
    when isMainModule:
      var
        a = initPerson(3, "foo")
        b = newPerson(4, "bar")
    
      echo a.name & " " & $a.age
      echo b.name & " " & $b.age
    
    正如您所见,代码基本相同,但存在一些差异:

    • 区分初始化的典型方法是对值类型使用init,对引用类型使用new。另外,请注意,Nim自己的标准库错误地使用了此约定,因为某些代码早于此约定(例如newStringOfCap不返回对字符串类型的引用)
    • 根据构造函数实际执行的操作,
      ref
      版本允许您返回一个
      nil
      值,您可以将其视为错误,而值构造函数强制您引发异常或更改构造函数以使用下面提到的var表单,以便您可以返回一个表示成功的bool。失败往往以不同的方式处理
    • 在类C语言中,有一种显式语法来访问指针的内存值或指针指向的内存值(解引用)。在Nim中也有空的下标符号(
      []
      )。但是,编译器将尝试自动放置这些内容,以避免代码混乱。因此,本例不使用它们。为了证明这一点,您可以将代码更改为:

      echo b[]姓名和$b[]年龄

      它将按预期工作和编译。但以下更改将产生编译器错误,因为您无法取消引用非引用类型:

      echo a[].name&''和$a[].age

    • Nim社区当前的趋势是区分值和引用类型。在旧的约定中,您将有一个
      TPerson
      ,参考值的别名为
      PPerson=ref TPerson
      。您可以发现许多代码仍然使用此约定

    • 根据对象和构造函数需要执行的具体操作,除了使用
      initPerson
      返回值之外,还可以使用
      init(x:var Person,…)
      。但是隐式
      result
      变量的使用允许编译器对此进行优化,因此它更像是一种味觉偏好或向调用者传递
      bool
      的要求
      • 它可以是

        type Student = object ...
        
        大致相当于

        typedef struct { ... } Student;
        
        typedef struct { ... } *Student;
        
        在C中,而

        type Student = ref object ...
        

        大致相当于

        typedef struct { ... } Student;
        
        typedef struct { ... } *Student;
        

        在C中(使用
        ref
        表示垃圾收集器跟踪的引用,而
        ptr
        不跟踪)。

        对此进行投票的人能否重新表述?我很难理解这个问题。@SimonWhitehead,我更新了这个问题(从更新的答案中,我将提炼出我原始问题的答案:-D)。所以基本上你有C++-比如--
        var student=student('Joe Doe')
        ,你有堆栈上的数据,或者
        var student=new student('Joe Doe'))
        并且您有指向堆上分配的数据的指针,对吗?是。我用一种典型的Nimrod方法扩展了答案,即用构造函数过程初始化这两种类型。该示例使用git版本的Nimrod进行了测试,可能无法直接使用上一个稳定的0.9.2版本。+1,非常好,谢谢。为了理解这个模型,我只遗漏了两件事——你能拿一个
        a
        (查看你的代码)指针吗?根据答案——如果您不定义
        newPerson
        ,您可以创建对
        Person
        对象的指针/引用吗?您可以通过addr操作符获得指向var的指针(请参阅),但它不像ref那样被垃圾收集。
        newPerson
        过程只是一个方便的过程,没有什么可以阻止您直接编写它的主体,请定义
        var c:ref Person
        并调用
        new(c)
        来分配它。再次感谢您!你提供的链接也解释了很多