假设我要实现一个简单的装饰器@notifyme,在调用装饰函数时打印一条消息。我希望装饰器接受一个参数来打印定制消息;参数(以及参数周围的括号)可以省略,在这种情况下将打印默认消息:
@notifyme('Foo is invoked!')
def foo():
pass
@notifyme # instead of @notifyme()
def bar():
pass
Run Code Online (Sandbox Code Playgroud)
为了允许省略括号,我必须提供以下两种实现@notifyme:
第一个实现允许用户自定义消息,因此它接受一个字符串作为参数并返回一个装饰器:
def notifyme_customized(message: str) -> Callable[[Callable], Callable]:
def decorator(func: Callable) -> Callable:
def decorated_func(*args, **kwargs):
print(str)
return func(*args, **kwargs)
return decorated_func
return decorator
Run Code Online (Sandbox Code Playgroud)
第二个实现本身是一个装饰器,并使用第一个实现来打印默认消息:
def notifyme_default(func: Callable) -> Callable:
return notifyme_customized('The function is invoked.')(func)
Run Code Online (Sandbox Code Playgroud)
为了使上面的两个实现使用相同的名称notifyme,我曾经functools.singledispatch动态地将调用分派notifyme到两个实现之一:
# This is a complete minimal reproducible example
from functools import singledispatch
from typing import Callable …Run Code Online (Sandbox Code Playgroud) 我希望在C中实现动态调度的提示(最好通过一个很好的例子).
我正在学习C并且作为练习,我想使用动态调度虚拟方法表从Java转换为C.
例如我有一个java代码:
abstract class Foo {
public abstract int val();
public abstract Boolean error();
}
class Fail extends Foo {
public int val(){ return 0;}
public Boolean error(){return true;}
}
class IntFoo extends Foo {
int v;
public IntFoo(int value){this.value=v;}
public int val(){ return v;}
public Boolean error(){return False;}
}
Run Code Online (Sandbox Code Playgroud)
我可以翻译一些像这样的基本内容:
typedef struct Foo{
void(**vtable);
}Foo;
typedef struct Fail{
void(**vtable);
struct Foo inherited;
}Fail;
typedef struct IntFoo{
void(**vtable);
struct Foo inherited;
}IntFoo;
Run Code Online (Sandbox Code Playgroud)
我在试图完成这个时遇到困难,因为我不知道:
vtable以便编译器识别正确的调用方法.关联名称太多:早期和晚期绑定,静态和动态调度,运行时与编译时多态等等,我不明白其中的区别.
我找到了明确的解释,但这是正确的吗?我会解释JustinC:
绑定:是确定变量的类型(对象?).如果它在编译时完成,它的早期绑定.如果它是在运行时完成的,那就是后期绑定.
Dispatch:确定哪个方法与方法调用匹配.Static Dispatch是编译时的计算方法,而动态调度是在运行时执行的.
绑定是否将原始值和引用变量分别与原始值和对象进行匹配?
编辑:请给我一些明确的参考资料,以便我可以阅读更多相关信息.
java late-binding dynamic-dispatch early-binding static-dispatch
使用不同的模式运行new_foo1并new_foo2返回相同的特征Foo。new_foo1除了更冗长之外,我没有看到它们之间有任何功能差异。两者之间有优选的方式吗?这两种模式有什么微妙的影响吗?
trait Foo {
fn bar(&self);
}
struct FooIm {}
impl Foo for FooIm {
fn bar(&self) {
println!("bar from FooIm")
}
}
fn new_foo1<'a>() -> &'a (dyn Foo + 'a) {
&FooIm {}
}
fn new_foo2() -> Box<dyn Foo> {
let f = FooIm {};
Box::new(f)
}
fn main() {
let f1 = new_foo1();
let f2 = new_foo2();
f1.bar();
f2.bar();
}
Run Code Online (Sandbox Code Playgroud) 有没有像在PHP中那样在Java中使用魔术方法的方法__call?
例如:
class foo {
@Setter @Getter
int id;
@Getter
Map <String, ClassInFoo> myMap;
protected class ClassInFoo {
@Setter @Getter
String name;
}
@Setter
String defaultKey;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用Project Lombok注释来获取getter和setter方法来简化代码.
让我们考虑我的地图包含由String映射的几个项目,defaultKey定义默认项目.
我想要的是能够调用foo.getName()哪个会返回默认名称foo.myMap.get(defaultKey).getName().
我不能手动编写所有getter的原因是Foo类实际上是继承了泛型,而内部类可能是不同的.
我有点需要:
function Object __call(method) {
if (exist_method(this.method)
return this.method();
else
return this.myMap.get(defaultKey).method();
}
Run Code Online (Sandbox Code Playgroud)
这在Java中是否可行?
编辑:
我做了一个更精确的例子,说明我想在这里实现的目标:https://gist.github.com/1864457
这样做的唯一原因是"简写"内部类中的方法.
我来自Ruby,并且采用了单一责任原则,封装,松耦合,小可测试方法等方法,因此我的代码往往会频繁地从一个方法跳到另一个方法.这就是我习惯在Ruby世界中工作的方式.我认为这是最好的工作方式,主要用于BDD,因为一旦你开始使用"大"方法做多件事,测试变得非常困难.
我想知道这种方法是否有任何缺点,只要性能有显着差异?
我希望能够分派函数的不同实现,不仅基于第一个参数的类型,而且基于任意谓词.目前我必须这样做:
def f(param):
try:
if param > 0:
# do something
except TypeError:
pass
try:
if all(isinstance(item, str) for item in param):
# do something else
except TypeError:
raise TypeError('Illegal input.')
Run Code Online (Sandbox Code Playgroud)
这是我希望能够做到的精神:
@generic
def f(param):
raise TypeError('Illegal input.') # default
@f.when(lambda param: param > 0)
def f_when_param_positive(param):
# do something
@f.when(lambda param: all(isinstance(item, str) for item in param))
def f_when_param_iterable_of_strings(param):
# do something else
Run Code Online (Sandbox Code Playgroud)
它类似于Python 3 singledispatch,但singledispatch只支持对类型的调度,而不支持任意谓词.
TL; DR:是否有一个库允许基于任意谓词(不仅是参数的类型)的基于谓词的函数调度?
我正在玩dynRust 1.27中引入的特性,并且偶然发现了这个编译错误:
error[E0433]: failed to resolve. Use of undeclared type or module `dyn`
--> src\main.rs:1:30
|
1 | fn _run0() -> Result<(), Box<dyn ::std::error::Error>> { Ok(()) }
| ^^^ Use of undeclared type or module `dyn`
Run Code Online (Sandbox Code Playgroud)
所有其他变种编译正常:
fn _run0() -> Result<(), Box<dyn ::std::error::Error>> { Ok(()) } // Error
fn _run1() -> Result<(), Box<dyn std::error::Error>> { Ok(()) } // Ok
fn _run2() -> Result<(), Box<::std::error::Error>> { Ok(()) } // Ok
Run Code Online (Sandbox Code Playgroud)
这是打算行为吗?
rustc 1.27.0(3eda71b00 2018-06-19)
(这个问题应该通过对Stroustrup的引用来回答.)
能够请求指向最派生类的指针似乎非常有用,如下所示:
class Base { ... };
class DerivedA { ... };
class DerivedB { ... };
class Processor
{
public:
void Do(Base* b) {...}
void Do(DerivedA* d) {...}
void Do(DerivedB* d) {...}
};
list<Base*> things;
Processor p;
for(list<Base*>::iterator i=things.begin(), e=things.end(); i!=e; ++i)
{
p.Do(CAST_TO_MOST_DERIVED_CLASS(*i));
}
Run Code Online (Sandbox Code Playgroud)
但是c ++中没有提供这种机制.为什么?
更新,激励示例:
假设您没有Base和Derived and Processor,而是拥有:
class Fruit
class Apple : public Fruit
class Orange: public Fruit
class Eater
{
void Eat(Fruit* f) { ... }
void Eat(Apple* f) { Wash(f); ... }
void …Run Code Online (Sandbox Code Playgroud) 正如"四人帮"在" 设计模式 "中所述:" 人们经常说 '继承打破了封装'",在"面向对象编程语言中的封装和继承"中解释Snyder.
然而,每次我读" 继承断裂包封 ",这要求背后的原因要么依稀解释的,或与所述的一个例子说明脆基类的问题.
在阅读论文时,我感觉真正打破封装的唯一继承属性是downcalls,这是开放递归(动态调度打开this)允许的特性,并定义为"当超类方法调用在子类中重写的方法时",根据Ruby&Leavens在"安全地创建正确的子类而不看超类代码"中的说法.
此外,根据Aldrich在"选择性开放递归:脆弱基类问题的解决方案"中的说法,开放递归显然是导致脆弱基类问题的原因.
因此,如果脆弱基类问题是"继承打破封装"的唯一原因,那么可以更清楚地说,下调会破坏封装.由于存在一些解决方案以避免在使用继承时进行下调,因此继承本身并不真正涉及破坏封装.此外,四人帮提出的取消继承的委托模式也可以允许开放递归和下调,因为委托人的context(this)由委托使用(这可能导致一种脆弱的委托类问题).
因此,我的问题是:
脆弱的基类问题是否被称为"继承打破封装"的唯一原因?
dynamic-dispatch ×10
java ×3
inheritance ×2
late-binding ×2
python ×2
rust ×2
c ×1
c++ ×1
callable ×1
libraries ×1
lombok ×1
objective-c ×1
oop ×1
performance ×1
polymorphism ×1
python-3.8 ×1
rtti ×1
vtable ×1