D中有"deleter"吗?
Is there a "deleter" in D?
有没有办法在 D 中实现 删除器?我找不到任何参考资料。在下面的示例中,我想使用 deleter 将 internal
的值重置回其原始状态。如果没有 deleter 这样的东西,那么实现上述要求的首选和惯用方法是什么? (如果是这样,我也对设计选择感兴趣,为什么这种类型的 属性 函数不是语言的一部分?)
class Class
{
private uint internal = 0;
@property uint value()
{
return this.internal;
}
@property uint value(uint input)
{
return this.internal = input;
}
}
更新:
根据下面的对话:我给出了一个虚拟示例,这让我们想到,我正在寻找的这种机制可以通过简单的 setter 和 .init
属性值的用法。然而事实并非如此。如果这个 属性 基本上只是几个函数调用的方便包装器怎么办?就像一些重置语义相关状态的 C 函数调用——这正是我的情况。
为了进一步澄清,我们正在谈论 Python 具有的类似机制,它支持 getter、setter 和 删除器.
因为我以前从未听说过删除器,所以我最初回答的问题与被问到的问题有些不同。 D 没有任何类似 Python 的删除器,下面的建议不能称为惯用的,但它本质上做同样的事情并且看起来有些相似。
请注意,这将导致可空类型的非直观行为 - a.value = null;
将调用特殊删除函数,而 a.value = cast(Foo*)null;
将调用常规 setter。所以你可能根本不应该这样做。
一种更惯用的方法是拥有一个单独的 clearValue()
函数,或者在值设置为其 'deleted' 值(空值、0 或其他值)时进行自动清理。
class Class
{
private uint internal = 0;
@property uint value()
{
return this.internal;
}
@property uint value(uint input)
{
return this.internal = input;
}
// deleter
@property uint value(typeof(null) input)
{
DoSpecialCleanup();
return this.internal = internal.init;
}
}
unittest
{
auto c = new Class();
c.value = 13;
assert(c.value == 13);
c.value = null; // Calling deleter here.
assert(c.value == 0);
}
在我对这个问题的最初(错误)理解中,我将其理解为将所有字段重置为其初始值。这可以通过以下代码完成:
import std.traits;
void reset(T)(auto ref T t) if (is(T == Unqual!T)) {
static if (is(T == class)) {
auto data = T.classinfo.initializer[0..$];
foreach (e; FieldNameTuple!T) {
alias FieldType = typeof(__traits(getMember, T, e));
enum offset = __traits(getMember, T, e).offsetof;
static if (is(FieldType == Unqual!FieldType)) {
__traits(getMember, t, e) = *cast(FieldType*)data[offset..$];
}
}
} else static if (!is(typeof(t = T.init))) {
foreach (e; FieldNameTuple!T) {
alias FieldType = typeof(__traits(getMember, T, e));
static if (is(FieldType == Unqual!FieldType)) {
__traits(getMember, t, e) = __traits(getMember, T.init, e);
}
}
} else {
t = T.init;
}
}
class Bar {
align(16):
int n = 3;
const int n2 = 19;
}
struct Baz {
align(16):
int n = 3;
const int n2 = 19;
}
unittest {
Bar b = new Bar();
b.n = 14;
reset(b);
assert(b.n == 3);
Baz b2;
b2.n = 14;
reset(b2);
assert(b2.n == 3);
}
简而言之 - 没有,D中没有deleter(a la Python)。[中的删除器=30=] 的存在主要是因为 Python 的 动态性质 。
Python3 示例:
class MyType():
"""Demonstrates the use of the *deleter* ...
"""
def __init__(self):
self._someval = None
@property
def someval(self):
return self._someval
@someval.setter
def someval(self, value):
self._someval = value
@someval.deleter
def someval(self):
print('someval about to be deleted')
del self._someval
if __name__ == '__main__':
obj = MyType()
obj.someval = 42
print(obj.someval)
del obj.someval # we trigger the deleter here
print(obj.someval) # AttributeError thrown...
在上面的这个简单示例中,很明显成员 "variable" 'someval' 是动态创建的(在 Python 中,这些都只是字典中的键...)并且作为使用 del Python 关键字可以很容易地 unset/destroyed。
在 D 中,这是不可能的,原因很明显 - 在 D 中,您不能动态取消设置属性! - 只要对象存在,所有成员就存在。 D 的 属性 机制(非常简单,但有效)不提供删除器 - 只有 getter 和 setter 可用,这一切都有意义...
有没有办法在 D 中实现 删除器?我找不到任何参考资料。在下面的示例中,我想使用 deleter 将 internal
的值重置回其原始状态。如果没有 deleter 这样的东西,那么实现上述要求的首选和惯用方法是什么? (如果是这样,我也对设计选择感兴趣,为什么这种类型的 属性 函数不是语言的一部分?)
class Class
{
private uint internal = 0;
@property uint value()
{
return this.internal;
}
@property uint value(uint input)
{
return this.internal = input;
}
}
更新:
根据下面的对话:我给出了一个虚拟示例,这让我们想到,我正在寻找的这种机制可以通过简单的 setter 和 .init
属性值的用法。然而事实并非如此。如果这个 属性 基本上只是几个函数调用的方便包装器怎么办?就像一些重置语义相关状态的 C 函数调用——这正是我的情况。
为了进一步澄清,我们正在谈论 Python 具有的类似机制,它支持 getter、setter 和 删除器.
因为我以前从未听说过删除器,所以我最初回答的问题与被问到的问题有些不同。 D 没有任何类似 Python 的删除器,下面的建议不能称为惯用的,但它本质上做同样的事情并且看起来有些相似。
请注意,这将导致可空类型的非直观行为 - a.value = null;
将调用特殊删除函数,而 a.value = cast(Foo*)null;
将调用常规 setter。所以你可能根本不应该这样做。
一种更惯用的方法是拥有一个单独的 clearValue()
函数,或者在值设置为其 'deleted' 值(空值、0 或其他值)时进行自动清理。
class Class
{
private uint internal = 0;
@property uint value()
{
return this.internal;
}
@property uint value(uint input)
{
return this.internal = input;
}
// deleter
@property uint value(typeof(null) input)
{
DoSpecialCleanup();
return this.internal = internal.init;
}
}
unittest
{
auto c = new Class();
c.value = 13;
assert(c.value == 13);
c.value = null; // Calling deleter here.
assert(c.value == 0);
}
在我对这个问题的最初(错误)理解中,我将其理解为将所有字段重置为其初始值。这可以通过以下代码完成:
import std.traits;
void reset(T)(auto ref T t) if (is(T == Unqual!T)) {
static if (is(T == class)) {
auto data = T.classinfo.initializer[0..$];
foreach (e; FieldNameTuple!T) {
alias FieldType = typeof(__traits(getMember, T, e));
enum offset = __traits(getMember, T, e).offsetof;
static if (is(FieldType == Unqual!FieldType)) {
__traits(getMember, t, e) = *cast(FieldType*)data[offset..$];
}
}
} else static if (!is(typeof(t = T.init))) {
foreach (e; FieldNameTuple!T) {
alias FieldType = typeof(__traits(getMember, T, e));
static if (is(FieldType == Unqual!FieldType)) {
__traits(getMember, t, e) = __traits(getMember, T.init, e);
}
}
} else {
t = T.init;
}
}
class Bar {
align(16):
int n = 3;
const int n2 = 19;
}
struct Baz {
align(16):
int n = 3;
const int n2 = 19;
}
unittest {
Bar b = new Bar();
b.n = 14;
reset(b);
assert(b.n == 3);
Baz b2;
b2.n = 14;
reset(b2);
assert(b2.n == 3);
}
简而言之 - 没有,D中没有deleter(a la Python)。[中的删除器=30=] 的存在主要是因为 Python 的 动态性质 。
Python3 示例:
class MyType():
"""Demonstrates the use of the *deleter* ...
"""
def __init__(self):
self._someval = None
@property
def someval(self):
return self._someval
@someval.setter
def someval(self, value):
self._someval = value
@someval.deleter
def someval(self):
print('someval about to be deleted')
del self._someval
if __name__ == '__main__':
obj = MyType()
obj.someval = 42
print(obj.someval)
del obj.someval # we trigger the deleter here
print(obj.someval) # AttributeError thrown...
在上面的这个简单示例中,很明显成员 "variable" 'someval' 是动态创建的(在 Python 中,这些都只是字典中的键...)并且作为使用 del Python 关键字可以很容易地 unset/destroyed。
在 D 中,这是不可能的,原因很明显 - 在 D 中,您不能动态取消设置属性! - 只要对象存在,所有成员就存在。 D 的 属性 机制(非常简单,但有效)不提供删除器 - 只有 getter 和 setter 可用,这一切都有意义...