作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在一些实际可以接受的极少数情况下,例如在单元测试中,您可能想要获取或设置私有(private)属性的值,或者在不可行的情况下调用某个类型的私有(private)方法。真的不可能吗?如果没有,你怎么能做到呢?
最佳答案
有两种方法可以访问类型的私有(private)方法,一种方法是获取私有(private)属性。除了第一种调用私有(private)方法的方法外,所有方法都需要元编程,其解释仍然涉及元编程。
例如,我们将实现 Hidden
使用私有(private)属性和 Password
隐藏值的类使用 Hidden
的类存储密码。 不要将此示例复制到您自己的代码中。这不是您合理处理密码的方式;这仅仅是为了举例。
调用私有(private)方法
信任其他类Metamodel::Trusting
是元角色,它实现高阶工作(类型的类型或种类,以下称为 HOW)所需的行为,以便能够信任其他类型。 Metamodel::ClassHOW
(类,并通过扩展,语法)是 Rakudo 中唯一内置的执行此角色的 HOW。trusts
是一个关键字,可在包内使用以允许另一个包调用其私有(private)方法(这不包括私有(private)属性)。例如,密码容器类的粗略实现可能看起来像这样使用 trusts
:
class Password { ... }
class Hidden {
trusts Password;
has $!value;
submethod BUILD(Hidden:D: :$!value) {}
method new(Hidden:_: $value) {
self.bless: :$value
}
method !dump(Hidden:D: --> Str:D) {
$!value.perl
}
}
class Password {
has Hidden:_ $!value;
submethod BUILD(Password:D: Hidden:D :$!value) {}
method new(Password:_: Str:D $password) {
my Hidden:D $value .= new: $password;
self.bless: :$value
}
method !dump(Password:D: --> Str:D) {
qc:to/END/;
{self.^name}:
$!value: {$!value!Hidden::dump}
END
}
method say(Password:D: --> Nil) {
say self!dump;
}
}
my Password $insecure .= new: 'qwerty';
$insecure.say;
# OUTPUT:
# Password:
# $!value: "qwerty"
#
使用 ^find_private_method 元方法
Metamodel::PrivateMethodContainer
是一个元角色,它实现了应该能够包含私有(private)方法的 HOW 的行为。
Metamodel::MethodContainer
和
Metamodel::MultiMethodContainer
是实现方法行为的其他元角色,但这里不会讨论这些。
Metamodel::ClassHOW
(类,并通过扩展,语法),
Metamodel::ParametricRoleHOW
和
Metamodel::ConcreteRoleHOW
(角色)和
Metamodel::EnumHOW
(enums) 是 Rakudo 内置的 HOWs 来完成这个角色。
Metamodel::PrivateMethodContainer
之一的方法是
find_private_method
,它将一个对象和一个方法名称作为参数,并返回
Mu
当没有找到时,或者
Method
代表您正在查找的方法的实例。
trusts
关键字通过删除使
Hidden
的行信任
Password
和改变
Password!dump
对此:
method !dump(Password:D: --> Str:D) {
my Method:D $dump = $!value.^find_private_method: 'dump';
qc:to/END/;
{self.^name}:
$!value: {$dump($!value)}
END
}
获取和设置私有(private)属性
Metamodel::AttributeContainer
是为应该包含属性的类型实现行为的元角色。与方法不同,这是处理所有类型属性所需的唯一元角色。 Rakudo 内置的 HOW,
Metamodel::ClassHOW
(类,并通过扩展,语法),
Metamodel::ParametricRoleHOW
和
Metamodel::ConcreteRoleHOW
(角色),
Metamodel::EnumHOW
(枚举)和
Metamodel::DefiniteHOW
(在内部用作值
self
绑定(bind)到公共(public)属性的访问器方法中)执行此角色。
Metamodel::AttributeContainer
添加到 HOW 是
get_attribute_for_usage
,给定一个对象和一个属性名称,如果没有找到属性则抛出,否则返回
Attribute
代表您正在查找的属性的实例。
Attribute
是 Rakudo 在内部存储属性的方式。
Attribute
的两种方法我们在这里关心的是
get_value
,它接受一个包含
Attribute
的对象实例并返回其值,以及
set_value
,它接受一个包含
Attribute
的对象实例和一个值,并设置它的值。
Hidden
没有实现
dump
像这样的私有(private)方法:
class Hidden {
has $!value;
submethod BUILD(Hidden:D: :$!value) {}
method new(Hidden:_: $value) {
self.bless: :$value;
}
}
class Password {
has Hidden:_ $!value;
submethod BUILD(Password:D: Hidden:D :$!value) {}
method new(Password:_: Str:D $password) {
my Hidden:D $value .= new: $password;
self.bless: :$value
}
method !dump(Password:D: --> Str:D) {
my Attribute:D $value-attr = $!value.^get_attribute_for_usage: '$!value';
my Str:D $password = $value-attr.get_value: $!value;
qc:to/END/;
{self.^name}:
$!value: {$password.perl}
END
}
method say(Password:D: --> Nil) {
say self!dump;
}
}
my Password:D $secure .= new: 'APrettyLongPhrase,DifficultToCrack';
$secure.say;
# OUTPUT:
# Password:
# $!value: "APrettyLongPhrase,DifficultToCrack"
#
常见问题
{ ... }
做什么?
qc:to/END/
做什么?
q:to/END/
之前,它允许您编写多行字符串。添加
c
之前
:to
允许将闭包嵌入到字符串中。
Metamodel::GrammarHOW
,它是
Metamodel::ClassHOW
的子类.
关于metaprogramming - 您如何从它们所属的类型之外访问私有(private)方法或属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57982956/
我是一名优秀的程序员,十分优秀!