我怎样才能安全地引用 Nim 中的现有对象?
How can I get safe reference to existing object in Nim?
我写了一个 Nim 程序,将两个对象作为 var
参数。它们每个都是具有 int
字段 level
的对象。在执行程序的实际工作之前,我想将参数按 level
较大的顺序排列,所以我这样做:
proc subroutine(param1: var MyObject, param2: var MyObject) =
var large: ptr MyObject = param1.addr
var small: ptr MyObject = param2.addr
# If in wrong order by level, swap large and small
if large.level < small.level:
large = param2.addr
small = param1.addr
# The rest of the proc references, only variables large and small, e.g.,
large.level += 1
small.level += 2
这似乎适用于我的应用程序,但我注意到在 Nim documentation 中,ptr
类型被称为“不安全”,建议仅用于低级别操作。有一个“安全”的引用类型ref
,建议使用ref
,除非你真的想做手动内存管理。
我不想进行手动内存管理,我希望 Nim 垃圾收集器为我处理这些参数的内存,但我没有找到安全的方法ref
' s 到两个参数。
我真的希望能够根据变量 large
和 small
而不是 [=21] 来编写算法(比我展示的简单代码复杂得多) =] 和 param2
。否则,如果我只能引用参数 param1
和 param2
,而不为它们创建这些别名,我将不得不复制并粘贴相同的算法两次以分别处理 param1.level < param2.level
和 param1.level < param2.level
的情况param1.level >= param2.level
.
是否有更惯用的 Nim 方法来做这样的事情,而不使用 ptr
类型?
您无法将 safe 对象变成 unsafe 反之亦然,除非执行对象的复制。
普通变量存储在堆栈中,因此当它们的函数范围存在时将被销毁,但引用可以存储到全局变量中并在以后访问。如果这是可能的,为了安全起见,compiler/language 需要知道某种方法 从堆栈中提取 变量,以便它在其作用域存在后仍然有效,或者在你背后手动执行复制,或其他神奇的事情。
这也是获取变量地址不安全的原因。您不能保证它的生命周期,因为您可以将该地址存储在其他地方并稍后尝试使用它。但是,就内存保证而言,这些变量至少应在您的 proc 调用期间保持活动状态,因此在该 proc 中使用这些地址别名应该是安全的,无需担心。
就是说,您可以重写代码以使用执行检查的中间代理过程,从而在每个 槽 中传递正确的变量。中间proc保证其中一个变量永远很大,可以避免使用不安全的引用:
type
MyObject = object
level: int
proc subroutine_internal(large: var MyObject, small: var MyObject) =
assert large.level >= small.level
large.level += 1
small.level += 2
proc subroutine(param1: var MyObject, param2: var MyObject) =
if param1.level < param2.level:
subroutine_internal(param2, param1)
else:
subroutine_internal(param1, param2)
proc main() =
var
a = MyObject(level: 3)
b = MyObject(level: 40)
subroutine(a, b)
echo a, b
main()
type
MyObject = object
level: int
proc subroutine(param1, param2: var MyObject) =
if param1.level > param2.level:
swap(param1, param2)
echo param1.level
echo param2.level
var
p1 = MyObject(level: 7)
p2 = MyObject(level: 3)
subroutine(p1, p2)
p2.level = 13
subroutine(p1, p2)
Nim 有针对这种情况的特殊 swap() 过程。 Var参数在内部作为指针传递,所以在参数传递中不涉及复制,swap应该尽可能优化复制。
当然,在某些情况下,使用 ref 对象而不是值对象会有优势。 Nim 的引用是托管指针。您可以在教程中找到更多信息,我的位于 http://ssalewski.de/nimprogramming.html#_value_objects_and_references.
我写了一个 Nim 程序,将两个对象作为 var
参数。它们每个都是具有 int
字段 level
的对象。在执行程序的实际工作之前,我想将参数按 level
较大的顺序排列,所以我这样做:
proc subroutine(param1: var MyObject, param2: var MyObject) =
var large: ptr MyObject = param1.addr
var small: ptr MyObject = param2.addr
# If in wrong order by level, swap large and small
if large.level < small.level:
large = param2.addr
small = param1.addr
# The rest of the proc references, only variables large and small, e.g.,
large.level += 1
small.level += 2
这似乎适用于我的应用程序,但我注意到在 Nim documentation 中,ptr
类型被称为“不安全”,建议仅用于低级别操作。有一个“安全”的引用类型ref
,建议使用ref
,除非你真的想做手动内存管理。
我不想进行手动内存管理,我希望 Nim 垃圾收集器为我处理这些参数的内存,但我没有找到安全的方法ref
' s 到两个参数。
我真的希望能够根据变量 large
和 small
而不是 [=21] 来编写算法(比我展示的简单代码复杂得多) =] 和 param2
。否则,如果我只能引用参数 param1
和 param2
,而不为它们创建这些别名,我将不得不复制并粘贴相同的算法两次以分别处理 param1.level < param2.level
和 param1.level < param2.level
的情况param1.level >= param2.level
.
是否有更惯用的 Nim 方法来做这样的事情,而不使用 ptr
类型?
您无法将 safe 对象变成 unsafe 反之亦然,除非执行对象的复制。
普通变量存储在堆栈中,因此当它们的函数范围存在时将被销毁,但引用可以存储到全局变量中并在以后访问。如果这是可能的,为了安全起见,compiler/language 需要知道某种方法 从堆栈中提取 变量,以便它在其作用域存在后仍然有效,或者在你背后手动执行复制,或其他神奇的事情。
这也是获取变量地址不安全的原因。您不能保证它的生命周期,因为您可以将该地址存储在其他地方并稍后尝试使用它。但是,就内存保证而言,这些变量至少应在您的 proc 调用期间保持活动状态,因此在该 proc 中使用这些地址别名应该是安全的,无需担心。
就是说,您可以重写代码以使用执行检查的中间代理过程,从而在每个 槽 中传递正确的变量。中间proc保证其中一个变量永远很大,可以避免使用不安全的引用:
type
MyObject = object
level: int
proc subroutine_internal(large: var MyObject, small: var MyObject) =
assert large.level >= small.level
large.level += 1
small.level += 2
proc subroutine(param1: var MyObject, param2: var MyObject) =
if param1.level < param2.level:
subroutine_internal(param2, param1)
else:
subroutine_internal(param1, param2)
proc main() =
var
a = MyObject(level: 3)
b = MyObject(level: 40)
subroutine(a, b)
echo a, b
main()
type
MyObject = object
level: int
proc subroutine(param1, param2: var MyObject) =
if param1.level > param2.level:
swap(param1, param2)
echo param1.level
echo param2.level
var
p1 = MyObject(level: 7)
p2 = MyObject(level: 3)
subroutine(p1, p2)
p2.level = 13
subroutine(p1, p2)
Nim 有针对这种情况的特殊 swap() 过程。 Var参数在内部作为指针传递,所以在参数传递中不涉及复制,swap应该尽可能优化复制。
当然,在某些情况下,使用 ref 对象而不是值对象会有优势。 Nim 的引用是托管指针。您可以在教程中找到更多信息,我的位于 http://ssalewski.de/nimprogramming.html#_value_objects_and_references.