27

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

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

像 C++ - 你有值并与new你一起创建指向数据的指针(在这种情况下,变量可以保存指向指向...指向数据的指针的指针)?

或者像 C# 一样——您将 POD 类型作为值,但用户定义的对象具有引用(隐式)?

我发现只有解引用是自动的,就像在 Go 中一样。

改写。你定义你的新类型,比方说Student(名字,大学,地址)。你写:

var student ...?
  1. 保存实际student数据(Student类型/类)
  2. 保持student指向数据的指针
  3. 保持student指向数据指针的指针

或者从那些方面来说有些是不可能的?

4

2 回答 2

35

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

但是,请注意,即使您指定 aproc按值传递变量,如果编译器认为它可以加快执行速度并且同时是安全的,它也可以自由决定通过引用在内部传递它。实际上,我使用引用的唯一一次是当我将 Nim 类型导出到 C 并且必须确保 C 和 Nim 都指向相同的内存时。请记住,您始终可以检查nimcache目录中生成的 C 代码。然后您将看到varproc 中的参数只是指向其 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 形式,以便您可以返回表示成功的布尔值。失败往往以不同的方式对待。
  • 在类 C 语言中,有一种显式语法可以访问指针的内存值或指针指向的内存值(解除引用)。在 Nim 中也有,它是空下标符号 ( [])。但是,编译器将尝试自动放置这些以避免混乱代码。因此,该示例不使用它们。为了证明这一点,您可以将代码更改为:

    echo b[].name & " " & $b[].age

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

    echo a[].name & " " & $a[].age

  • Nim 社区当前的趋势是摆脱单字母前缀来区分值和引用类型。在约定中,您将有一个TPerson和一个参考值的别名作为PPerson = ref TPerson. 你会发现很多代码仍然使用这个约定。

  • 取决于你的对象和构造函数需要做什么,而不是initPerson返回值,你也可以有一个init(x: var Person, ...). 但是隐式变量的使用允许编译器对此进行优化,因此将 a 传递给调用者result更像是一种口味偏好或要求。bool
于 2014-02-28T15:40:10.217 回答
6

它可以是任何一个。

type Student = object ...

大致相当于

typedef struct { ... } Student;

在 C 中,而

type Student = ref object ...

或者

type Student = ptr object ...

大致相当于

typedef struct { ... } *Student;

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

于 2014-02-28T16:19:31.317 回答