如何从 Tcl 的超类中访问派生的 类 成员变量?
How does one access a derived classes member variables from within the superclass in Tcl?
代码:
package require TclOO
oo::class create Supe {
variable cape boots
constructor {} {
puts -nonewline "Supe: "
puts [info class variables [self class]]
}
}
oo::class create Clark {
superclass Supe
variable glasses suit
constructor {} {
puts -nonewline "Clark: "
puts [info class variables [self class]]
next
}
}
set hero [Clark new]
输出:
Clark: glasses suit
Supe: cape boots
是否可以从 Supe 的构造函数中获取 Clark 的成员变量列表而不将它们作为参数传递给 Supe?
最终,目标是从 dict 参数动态设置派生的 class 变量:
foreach {varName} [info class variables [self class]] {
variable $varName [dict get $args $varName]
}
如果上面的代码可以在superclass构造函数中使用,就可以避免将它放在每个派生的class构造函数中。
您可以使用 self object
或 self
获取对象的名称。然后,您可以使用 info object class
获取对象的 class。最后,你可以用 info class variables
.
得到一个 class 的成员变量
将所有内容放在一起得出:
[info class variables [info object class [self]]]
我的看法并没有增加已经给出的答案,而是着眼于 OP 的激励问题:
Ultimately, the goal is to dynamically set derived class variables
from a dict argument:
我过去一直使用的批量更新对象状态的方法是……。沿着:
oo::class create C {
variable a b
constructor {aDict} {
my variable {*}[lsort -unique [my lookupVars [info object class [self]]]]
# dict with aDict {;}
lassign [dict values $aDict] {*}[dict keys $aDict]
}
method lookupVars {currentClass} {
set v [info class variables $currentClass]
foreach scl [info class superclasses $currentClass] {
if {$scl eq "::oo::object"} {
break
}
lappend v {*}[my lookupVars $scl]
}
return $v
}
method print {} {
foreach v [info object vars [self]] {
my variable $v
puts "<$v> [set $v]"
}
}
}
关键项目是:
lookupVars
是一个自然递归的实现,遍历 class、直接和间接超级 classes 以收集定义的每个 class 变量。这是 Donal 描述的 "properties" 发现的后续。请注意,这在几个方面受到限制(例如,mixins 被忽略,TclOO 的内部线性化方案也没有反映,没有控制重复等)
lassign
可用于一次设置多个变量。或者,但有一些副作用,dict with
"loads" a given dict's content into variables available for the current scope. my variable ?varName ...?
将提供方法本地链接到收集的每个 class 变量。这样,您可以保存脚本级循环,而不必为不匹配的键过滤提供的字典。
观看:
oo::class create D {
superclass C
variable c d
}
oo::class create E {
superclass D
variable e f
}
[D new {a 1 b 2 c 3 d 4}] print
[E new {a 1 b 2 c 3 d 4 f 5 e 8 x 3}] print
[D new {a 1 b 2 c 3 d 4 f 5 x 3}] print
代码:
package require TclOO
oo::class create Supe {
variable cape boots
constructor {} {
puts -nonewline "Supe: "
puts [info class variables [self class]]
}
}
oo::class create Clark {
superclass Supe
variable glasses suit
constructor {} {
puts -nonewline "Clark: "
puts [info class variables [self class]]
next
}
}
set hero [Clark new]
输出:
Clark: glasses suit
Supe: cape boots
是否可以从 Supe 的构造函数中获取 Clark 的成员变量列表而不将它们作为参数传递给 Supe?
最终,目标是从 dict 参数动态设置派生的 class 变量:
foreach {varName} [info class variables [self class]] {
variable $varName [dict get $args $varName]
}
如果上面的代码可以在superclass构造函数中使用,就可以避免将它放在每个派生的class构造函数中。
您可以使用 self object
或 self
获取对象的名称。然后,您可以使用 info object class
获取对象的 class。最后,你可以用 info class variables
.
将所有内容放在一起得出:
[info class variables [info object class [self]]]
我的看法并没有增加已经给出的答案,而是着眼于 OP 的激励问题:
Ultimately, the goal is to dynamically set derived class variables from a dict argument:
我过去一直使用的批量更新对象状态的方法是……。沿着:
oo::class create C {
variable a b
constructor {aDict} {
my variable {*}[lsort -unique [my lookupVars [info object class [self]]]]
# dict with aDict {;}
lassign [dict values $aDict] {*}[dict keys $aDict]
}
method lookupVars {currentClass} {
set v [info class variables $currentClass]
foreach scl [info class superclasses $currentClass] {
if {$scl eq "::oo::object"} {
break
}
lappend v {*}[my lookupVars $scl]
}
return $v
}
method print {} {
foreach v [info object vars [self]] {
my variable $v
puts "<$v> [set $v]"
}
}
}
关键项目是:
lookupVars
是一个自然递归的实现,遍历 class、直接和间接超级 classes 以收集定义的每个 class 变量。这是 Donal 描述的 "properties" 发现的后续。请注意,这在几个方面受到限制(例如,mixins 被忽略,TclOO 的内部线性化方案也没有反映,没有控制重复等)lassign
可用于一次设置多个变量。或者,但有一些副作用,dict with
"loads" a given dict's content into variables available for the current scope.my variable ?varName ...?
将提供方法本地链接到收集的每个 class 变量。这样,您可以保存脚本级循环,而不必为不匹配的键过滤提供的字典。
观看:
oo::class create D {
superclass C
variable c d
}
oo::class create E {
superclass D
variable e f
}
[D new {a 1 b 2 c 3 d 4}] print
[E new {a 1 b 2 c 3 d 4 f 5 e 8 x 3}] print
[D new {a 1 b 2 c 3 d 4 f 5 x 3}] print