浏览Rust文档的标记部分和维基百科有关子类型和方差的文章多次没有它提高我对生命周期子类型关系的理解,我感到愚蠢.
我想我只是习惯于"典型的OOP风格"子类型关系,比如"Cat <:Animal",意思是"Cat是动物的子类型",其中"S是T的子类型"意味着"任何术语S都可以安全在预期类型为T的术语中使用".到现在为止还挺好.
但这如何适用于生命周期?它现在在Rust中定义的方式显然是(*)
(#1)'a <:'b <=>生命周期a不超过生命周期b.
你可能会想"当然这意味着什么!" 可能是因为<:看起来类似于小于运算符或可能因为"sub"让你想到子集而且更短的寿命肯定是更长寿命的一个子集.但是' 如果'a'不再是'b',那么它' '真的是'b' 的子类型吗?让我们尝试应用维基百科对子类型关系的定义:
(#2)'a <:'b <=>生命周期a可以安全地用于预期寿命为b的上下文中.
我遇到的问题是我无法调和这个问题.你是如何从#2到#1的?因为对我来说,这似乎是一个矛盾...如果你期望某事至少是活着的b并且你有一个比b短的东西,你显然不能在那些有生命周期的东西中使用它是必需的,可以吗?它只是我还是我们得到了生命时间的子类型关系错误?
编辑:(*)根据#rustIRC频道中的Ms2ger,情况就是如此.它也适用于Items迭代器中使用的逆变寿命标记的文档.
Edit2:已删除ContravariantLifetime和CovariantLifetime标记.我们现在已经PhantomData作为标记模块的替代品.
代码转储道歉:
gameObject.cpp:
#include "gameObject.h"
class gameObject
{
private:
int x;
int y;
public:
gameObject()
{
x = 0;
y = 0;
}
gameObject(int inx, int iny)
{
x = inx;
y = iny;
}
~gameObject()
{
//
}
int add()
{
return x+y;
}
};
Run Code Online (Sandbox Code Playgroud)
gameObject.h:
class gameObject
{
private:
int x;
int y;
public:
gameObject();
gameObject(int inx, int iny);
~gameObject();
int add();
};
Run Code Online (Sandbox Code Playgroud)
错误:
||=== terrac, Debug ===|
C:\terrac\gameObject.cpp|4|error: redefinition of `class gameObject'|
C:\terrac\gameObject.h|3|error: previous definition of `class gameObject'| …Run Code Online (Sandbox Code Playgroud) 在最近的一个C++ 0x草案(n3225.pdf)中,我们可以找到5.1.2/10:
使用通常的非限定名称查找规则(3.4.1)查找捕获列表中的标识符; 每个这样的查找应该找到一个变量,其自动存储持续时间在本地lambda表达式的到达范围内声明.如果实体(即变量或此实体)出现在lambda表达式的捕获列表中,则称其被明确捕获.
这对我来说似乎相当严格.例如,在我看来,以下事情是不允许的:
int global;
struct s {
int x;
void memfun() {
[x,global]{};
}
};
Run Code Online (Sandbox Code Playgroud)
因为x不一定是具有自动存储的变量,也不是global.请注意,此捕捉条款的用意是让拉姆达对象存储复制的x,并global可能是可取的情况下,他们在后一阶段发生变化.我已经知道了另一种选择:
int global;
struct s {
int x;
void memfun() {
int copyx = x;
int copyglobal = global;
[copyx,copyglobal]{};
}
};
Run Code Online (Sandbox Code Playgroud)
但这归结为额外的副本和额外的锅炉板只是为了捕获x和global复制.
此外,我在最新的草稿中找不到任何结论,如果我们在捕获子句中命名本地引用会发生什么:
int main() {
int i = 0;
int &r = i;
assert([r]{return &r;}() != &i);
}
Run Code Online (Sandbox Code Playgroud)
lambda对象"复制引用"还是"复制int"?如果它通过副本捕获引用的对象,这可以节省我们之前的解决方案中的其他副本.
GCC显然支持所有这些示例,并在最后一种情况下存储一个int的副本(这是可取的,恕我直言).但我想知道这是否实际上是根据C++ 0x草案的预期行为,或者只是一个编译器扩展,分别是一个实现bug.
编辑: …
C++ 0x中的Lambda表达式/闭包如何使C++中的内存管理变得复杂?为什么有些人说封闭在手动内存管理的语言中没有位置?他们的要求是否有效,如果是,那背后的原因是什么?
c++ lambda programming-languages functional-programming c++11
编辑:让我尝试改写并改进我的问题.旧版本附在底部.
我正在寻找的是一种以类型通用的方式表达和使用自由函数的方法.例子:
abs(x) # maps to x.__abs__()
next(x) # maps to x.__next__() at least in Python 3
-x # maps to x.__neg__()
Run Code Online (Sandbox Code Playgroud)
在这些情况下,函数的设计方式允许具有用户定义类型的用户通过将工作委托给非静态方法调用来自定义其行为.这很好.它允许我们编写并不真正关心确切参数类型的函数,只要它们"感觉"像对某个概念建模的对象.
反例:一般不能轻易使用的功能:
math.exp # only for reals
cmath.exp # takes complex numbers
Run Code Online (Sandbox Code Playgroud)
假设,我想编写一个泛型函数,将exp应用于类似数字的对象列表.我应该使用什么exp函数?如何选择正确的?
def listexp(lst):
return [math.exp(x) for x in lst]
Run Code Online (Sandbox Code Playgroud)
显然,即使存在复数的exp(在cmath中),这也不适用于复数列表.它也不适用于任何用户定义的类似数字的类型,它可能提供自己的特殊exp函数.
所以,我正在寻找的是一种双方处理这种方式的方法 - 理想情况下,没有特殊的外壳很多东西.作为一些通用函数的编写者,它不关心参数的确切类型,我想使用特定于所涉及类型的正确数学函数,而不必明确地处理它.作为用户定义类型的编写者,我想公开已经扩充的特殊数学函数来处理存储在这些对象中的其他数据(类似于复数的虚部).
这样做的首选模式/协议/习惯用法是什么?我还没考试numpy.但我下载了它的源代码.据我所知,它为数组提供了sin函数.不幸的是,我还没有在源代码中找到它的实现.但是看看他们如何设法为阵列当前存储的正确类型的数字选择正确的sin函数将会很有趣.
在C++中,我会依赖于函数重载和ADL(依赖于参数的查找).在C++被静态类型化的情况下,在编译时完全处理这个(名称查找,重载解析)并不奇怪.我想,我可以在运行时使用Python和Python提供的反射工具来模拟它.但我也知道,尝试将编码风格导入另一种语言可能是一个坏主意,在新语言中并不是非常惯用.所以,如果你对方法有不同的想法,我会全力以赴.
我想,在某些地方,我需要以可扩展的方式手动执行一些类型相关的调度.也许写一个模块"tgmath"(类型泛型数学),它支持真实和复杂的支持,并允许其他人注册他们的类型和特殊情况函数......意见?Python大师对此有何评论?
TIA
编辑:显然,我不是唯一一个对泛型函数和类型相关的重载感兴趣的人.有PEP 3124但它自4年前就处于草案状态.
旧版本的问题:
我有很强的Java和C++背景,最近刚开始学习Python.我想知道的是:我们如何扩展数学函数(至少它们的名称),以便它们可以用于其他用户定义的类型?这些类型的函数是否提供了我可以利用的任何类型的扩展点/钩子(类似于next(obj)实际委托的迭代器协议obj.__next__等)?
在C++中,我会简单地用新参数类型重载函数,并让编译器使用参数表达式的静态类型来确定哪些函数意味着什么.但由于Python是一种非常动态的语言,因此不存在重载.这样做的首选Python方式是什么?
另外,当我编写自定义函数时,我想避免使用长链
if isinstance(arg,someClass):
suchandsuch
elif ...
Run Code Online (Sandbox Code Playgroud)
我可以使用哪些模式使代码看起来更漂亮,更多Python?
我想,我基本上是在尝试处理Python中缺少函数重载的问题.至少在C++中,重载和依赖于参数的查找是良好C++风格的重要组成部分.
是否有可能
x = udt(something) # object of user-defined …Run Code Online (Sandbox Code Playgroud) 对于我目前的项目,我一直在为Lua包装器编写大量的C/C++.其中大量是简单的setter和getter,所以我设法编写了一些模板,可以很容易地生成这些,如下所示:
// Class Return Field
template <typename T, typename U, U T::*Member>
int luaU_get(lua_State* L)
{
T* obj = luaW_check<T>(L, 1);
luaU_push<U>(L, obj->*Member);
return 1;
}
static luaL_reg Foo_Table[] =
{
...
// Now I can just use this generic template to avoid
// writing simple getter functions
{ "getbar", luaU_get<Foo, Bar, &Foo::bar> },
...
};
Run Code Online (Sandbox Code Playgroud)
我想为任意函数的简单函数包装器做类似的事情.例如,能够这样做会很高兴:
template <typename T, typename U, U (T::*Func)(), typename... Args>
int luaU_func(lua_State* L)
{
// ...?
}
static luaL_reg Foo_Table[] =
{
...
{ …Run Code Online (Sandbox Code Playgroud) 在下面的C++ 0x代码中,我尝试使用克隆成员函数(如果存在)克隆对象并回退到复制构造函数:
struct use_copy_ctor {};
struct prefer_clone_func : use_copy_ctor {};
template<class T>
auto clone(T const* ptr, prefer_clone_func)
-> decltype(ptr->clone())
{ return ptr->clone(); }
template<class T>
auto clone(T const* ptr, use_copy_ctor)
-> decltype(new T(*ptr))
{ return new T(*ptr); }
struct abc {
virtual ~abc() {}
virtual abc* clone() const =0;
};
struct derived : abc
{
derived* clone() const { return new derived(*this); }
};
int main()
{
derived d;
abc* p = &d;
abc* q = clone(p,prefer_clone_func());
delete q;
} …Run Code Online (Sandbox Code Playgroud) 我正在尝试在Rust中创建一个允许我编写的宏
make_list!(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
代替
Node::new(1, Node::new(2, Node::new(3, None)))
Run Code Online (Sandbox Code Playgroud)
哪个应该适用于任意数量的"参数",包括零.这是我到目前为止:
macro_rules! make_list(
() => (
None
);
( $x:expr, $( $more:expr ),* ) => (
Node::new($x, make_list!( $( $more ),* ))
)
);
Run Code Online (Sandbox Code Playgroud)
但是我收到以下错误:
error: unexpected end of macro invocation
--> src/main.rs:19:42
|
19 | Node::new($x, make_list!( $( $more ),* ))
| ^^^^^
Run Code Online (Sandbox Code Playgroud)
我无法理解这一点.从我所知,它应该工作.我做错了什么?
完整的代码:
type List<T> = Option<Box<Node<T>>>;
struct Node<T> {
value: T,
tail: List<T>,
}
impl<T> Node<T> {
fn new(val: T, tai: List<T>) -> List<T> {
Some(Box::new(Node::<T> { …Run Code Online (Sandbox Code Playgroud) 假设,我想开发一个通用库,它应该可以用于类似数字的类型,包括双重和用户定义的类型.我现在面临的问题是,我不知道如何编写函数模板的返回类型,就像这样:
template<class T>
auto transmogrify(T x)
-> ???
{
using std::abs;
return abs(x)+2.0;
}
Run Code Online (Sandbox Code Playgroud)
using声明使这个函数模板的主体适用于原始类型,因为它们没有关联的命名空间(因此没有ADL).但是我希望transmogrify使用专门的abs函数,以防用户定义类型的作者提供自己的abs函数.我不能简单地使用
-> decltype( abs(x)+2.0 )
Run Code Online (Sandbox Code Playgroud)
因为这不适用于比赛,因为std :: abs不在范围内(据我所知).但写作
-> decltype( std::abs(x)+2.0 )
Run Code Online (Sandbox Code Playgroud)
会禁用ADL.但禁用ADL不是一种选择.此外,专用abs函数返回的值可能不是T类型,而是某些其他类型.
关于如何解决返回类型问题的任何想法,同时(a)保持ADL和(b)回退到某些默认函数(如本例中的std :: abs),对于不提供专用abs的类型.
c++ generic-programming decltype argument-dependent-lookup c++11
我正在尝试在Rust中编写一些通用的数学函数,并且我一直遇到以下错误消息:
error: conflicting implementations for trait SoAndSo
Run Code Online (Sandbox Code Playgroud)
有可能解决问题吗?如果是这样,怎么样?
例如,我正在尝试编写一个带有两个迭代器的通用点积,拉链它们并迭代它们以积累产品.我希望这个功能也能够计算复值点产品.复数上的点积包括共轭一侧.我的第一个想法是Dot1为二元函数写一个特征来替换Mul,因为它也会使左侧参数共轭.这是完整的代码:
extern crate num;
use num::complex::Complex;
use num::{Float, Num};
trait Dot1<Rhs, Result> {
fn dot1(&self, rhs: Rhs) -> Result;
}
impl<T: Float> Dot1<T, T> for T {
// conjugation for reals is a no-op
fn dot1(&self, rhs: T) -> T {
*self * rhs
}
}
impl<T: Num + Clone> Dot1<Complex<T>, Complex<T>> for Complex<T> {
fn dot1(&self, rhs: Complex<T>) -> Complex<T> {
self.conj() * rhs
}
}
fn …Run Code Online (Sandbox Code Playgroud)