Rust 中的泛型部分专业化

2023-11-22

让我们看一些数学向量的例子。根据空间维度,它由不同数量的组件组成。

  • 对于 2D:x,y;
  • 对于 3D:x、y、z;
  • 对于 4D:x、y、z、w;
  • 通用:N 个组件。

在C++中我可以使用SFINAE概念来实现它。

template <size_t D, typename T, typename = void>
struct Vector;

// Implement for 2D
template<size_t D, typename T>
struct Vector <D, T, std::enable_if_t<(D == 2)>>
{
    T x;
    T y;
}

// Implement for 3D
template<size_t D, typename T>
struct Vector <D, T, std::enable_if_t<(D == 3)>>
{
    T x;
    T y;
    T z;
}
    
// Implement for 4D
template<size_t D, typename T>
struct Vector <D, T, std::enable_if_t<(D == 4)>>
{
    T x;
    T y;
    T z;
    T w;
}

我怎样才能在 Rust 中做同样的事情?


你不能像在 C++ 中专门化模板那样在 Rust 中专门化泛型。 (Rust 有一个特性叫做“专业化”,但它只适用于impls,这里并不真正相关。)Rust 泛型有时被称为“有原则的”,因为它们必须工作原则(声明后),不仅仅是在实践中(一旦实例化)。这是一个刻意的选择Rust 的设计者为了避免 C++ 中 SFINAE 的一些更混乱的后果。

我可以想到两种主要方法来实现与 Rust 中的 C++ 代码类似的效果,具体取决于代码的通用上下文。一种方法是使用特征作为类型级别函数来计算参数化结构的内容类型,这与 C++ 版本类似,但具有稍微更详细的字段访问(为简单起见,我会想象T is f32对于这些示例):

// types that contain the actual data
struct Vector2 {
    x: f32,
    y: f32,
}

struct Vector3 {
    x: f32,
    y: f32,
    z: f32,
}

// types that will be used to parameterize a type constructor
struct Fixed<const N: usize>;
struct Dynamic;

// a type level function that says what kind of data corresponds to what type
trait VectorSize {
    type Data;
}

impl VectorSize for Fixed<2> {
    type Data = Vector2;
}

impl VectorSize for Fixed<3> {
    type Data = Vector3;
}

impl VectorSize for Dynamic {
    type Data = Vec<f32>;
}

// pulling it all together
struct Vector<Z>(Z::Data) where Z: VectorSize;

现在,如果你有v: Vector<Fixed<2>>您可以使用v.0.x or v.0.y,而如果你有一个Vector<Dynamic>你必须使用v.0[0] and v.0[1]。但是没有办法编写一个使用的通用函数x and y这将适用于Vector<Fixed<2>> or Vector<Fixed<3>>;因为它们之间没有语义关系xs and ys,那是没有原则的。

另一种选择是将数组放入Vector并制作x and y访问元素 0 和 1 的便捷方法:

struct Vector<const N: usize> {
    xs: [f32; N],
}

impl<const N: usize> Vector<N> {
    fn x(&self) -> f32 where Self: SizeAtLeast<2> {
        self.xs[0]
    }

    fn y(&self) -> f32 where Self: SizeAtLeast<2> {
        self.xs[1]
    }
    
    fn z(&self) -> f32 where Self: SizeAtLeast<3> {
        self.xs[2]
    }
}

// In current Rust, you can't bound on properties of const generics, so you have
// to do something like this where you implement the trait for every relevant
// number. Macros can make this less tedious. In the future you should be able to
// simply add bounds on `N` to `x`, `y` and `z`.
trait SizeAtLeast<const N: usize> {}

impl SizeAtLeast<2> for Vector<2> {}
impl SizeAtLeast<2> for Vector<3> {}
impl SizeAtLeast<2> for Vector<4> {}

impl SizeAtLeast<3> for Vector<3> {}
impl SizeAtLeast<3> for Vector<4> {}

现在您可以编写适用于的通用函数Vector<N>并使用x and y,但要适应它以允许突变并不容易。一种方法是添加x_mut, y_mut and z_mut返回的方法&mut f32.

相关问题

  • 相当于 C++ 中 Rust 的特定模板用法
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rust 中的泛型部分专业化 的相关文章

随机推荐

  • 如何替换 SQL 中的左连接

    谁能告诉我如何在不真正使用左连接的情况下编写左连接的等效项 Select from a left join b on a name b name 请记住 SQL 的外连接是一种关系并集 专门用于投影空值 如果您想避免使用空值 在我看来这是一
  • 如何在 ASP.NET MVC 中对 ActionFilter 进行单元测试?

    有一个ActionFilter在我的控制器类上 这OnActionExecuting当在 Web 应用程序中调用控制器的操作时 方法将被调用 现在我打电话给Action在单元测试中 NiceController niceController
  • R:使用 mongolite 更新 mongodb 中的条目

    我有一个mongo包含我传递给某些人的信息的数据库R用于分析的脚本 我目前正在使用mongolite传递信息的包mongo to R 我在每个 mongo 条目中有一个名为checkedByR 这是一个二进制文件 指示该条目是否已被分析R已
  • Hibernate 标准:左外连接,对两个表都有限制

    我正在执行 LEFT OUTER JOIN 但我只能对第一个表应用限制 有没有办法也适用于第二张桌子 这是我的代码 Criteria criteria this crudService initializeCriteria Applican
  • 带大括号的 std::vector init 调用复制构造函数两次

    为什么当我用大括号初始化 std vector 时 std vector
  • Android ExpandableListView 带按钮的父级

    我正在努力实现这样的目标 可扩展列表由某些类别的名称组成 当单击父级时 它会显示该类别中所有子级的列表 现在 假设我想动态地将一个子项添加到任何类别中 我怎么做 我是否要为列表中的每个家长保留一个按钮 单击该按钮将在其下添加一个新孩子 但环
  • 这是在 C++11 中将一个 std::vector 的内容移动到另一个 std::vector 的末尾的最有效方法吗?

    我在想vector insert and std copy 命令需要额外的分配 然而 如果我push back 一个新创建的元素然后swap 我认为只要包含的类型不使用默认构造函数分配 这就会减少任何分配 我的问题实际上是专门针对std v
  • ILMerge + 本地化资源程序集

    我正在使用 ILMerge 从包含 1 个 exe 和 2 个资源 dll 的项目中创建单个程序集应用程序 bin 调试 test exe bin Debug nl BE test resources dll bin Debug fr FR
  • 如何用文档来修饰 Objective C 方法?

    当我输入 Cocoa 对象并调用该对象上的选择器时 有时我可以看到有关该方法的 文档 或 帮助 信息 例如 当我输入 NSArray alloc 我看到两个帮助提示 一个为NSArray 还有一个用于alloc 当我键入代码时 这两个内容都
  • 全局 jquery 函数

    我必须在最初加载的js文件中编写全局函数 我想在上面编写函数 以便可以从所有页面访问它 我是 jquery 新手 我想知道如何在js文件中编写函数并从其他页面调用它 您可以通过执行以下操作添加自己的 jQuery 函数 fn MyFunct
  • firebase-tools“-bash:firebase:找不到命令”

    很高兴 Firebase 的托管现已结束测试版 尝试使用 firebase tools 包 我已成功安装它 npm install g firebase tools 尝试运行任何工具都会失败 bash firebase command no
  • 在 R Shiny 应用程序中从反应性数据()调用变量

    我想在反应式表达式中调用某个变量 像这样的东西 server R library raster shinyServer function input output data lt reactive inFile lt input test
  • 如何用javapoet生成符号Class

    我想生成一个这样的字段 public static Map
  • 如何重建GNU Arm嵌入式工具链的newlib和newlib-nano

    我下载了工具链 gcc arm none eabi 6 2017 q2 update win32 sha1 exe Windows 来自https developer arm com open source gnu toolchain gn
  • javascript include 开头的双斜线

    我一直在查看 html5 样板并注意到 jquery include url 以双斜杠开头 网址是 ajax googleapis com ajax libs jquery 1 5 1 jquery min js 为什么 http 丢失了
  • 如何获取Web配置位置元素?

    如何获取Web配置位置元素 ConfigurationManager GetSection appSettings returns Okay ConfigurationManager GetSection location return n
  • Pyinstaller 语法错误:异步函数内的“yield”(Python 3.5.1)

    我正在尝试使用pyinstaller创建单个可执行文件以分发给未安装 Python 的用户 该脚本非常简单 只是为了测试水 我仅使用几行代码作为 豚鼠 The Hello World程序 无需导入 转换良好 我的豚鼠程序 导入matplot
  • matplotlib 图中交互式选择系列

    我一直在寻找一种方法 能够在创建绘图后选择绘图上可见的系列 我需要这个 因为我经常有很多系列的情节 它们太多了 无法同时绘制 我需要快速交互地选择哪些系列可见 理想情况下 会有一个窗口 其中包含绘图和复选框中的系列列表 其中带有选中复选框的
  • 共享 Git 存储库中的 .editorconfig

    我已经准备好了我的 editorconfig我想在多个 Git 存储库上使用的文件 每个存储库都包含一个 Visual Studio 解决方案 C 我的第一个想法是把 editorconfig文件放在自己的存储库中 然后将其作为子模块包含在
  • Rust 中的泛型部分专业化

    让我们看一些数学向量的例子 根据空间维度 它由不同数量的组件组成 对于 2D x y 对于 3D x y z 对于 4D x y z w 通用 N 个组件 在C 中我可以使用SFINAE概念来实现它 template