gpt4 book ai didi

metaprogramming - 您如何从它们所属的类型之外访问私有(private)方法或属性?

转载 作者:行者123 更新时间:2023-12-03 14:36:51 25 4
gpt4 key购买 nike

在一些实际可以接受的极少数情况下,例如在单元测试中,您可能想要获取或设置私有(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::MethodContainerMetamodel::MultiMethodContainer是实现方法行为的其他元角色,但这里不会讨论这些。 Metamodel::ClassHOW (类,并通过扩展,语法), Metamodel::ParametricRoleHOWMetamodel::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::ParametricRoleHOWMetamodel::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"
#
常见问题
什么 { ... }做什么?
这会 stub 一个包,允许您在实际定义它之前声明它。
什么 qc:to/END/做什么?
您可能已经看过 q:to/END/之前,它允许您编写多行字符串。添加 c之前 :to允许将闭包嵌入到字符串中。
为什么语法类是扩展类?
语法使用 Metamodel::GrammarHOW ,它是 Metamodel::ClassHOW 的子类.
你说 ^find_private_method 和 ^get_attribute_for_usage 将一个对象作为它们的第一个参数,但你在示例中省略了它。为什么?
在对象上调用元方法将自身作为第一个参数隐式传递。如果我们直接在对象的 HOW 上调用它们,我们会将对象作为第一个参数传递。

关于metaprogramming - 您如何从它们所属的类型之外访问私有(private)方法或属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57982956/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com