AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79221451
Accepted
cher-nov
cher-nov
Asked: 2024-11-25 10:19:57 +0800 CST2024-11-25 10:19:57 +0800 CST 2024-11-25 10:19:57 +0800 CST

为什么要通过 where 子句中绑定的通用特征来约束单位类型(如 `where () : Trait<…>`)?

  • 772

今天我在这里遇到了一个有点奇怪的语法 - where ():
https ://github.com/binator/self/tree/80ba2ade?tab=readme-ov-file#example

fn hex_primary<Stream, Context>(stream: Stream) -> Parsed<u8, Stream, Context>
where
  (): IntRadixParse<Stream, Context, u8>,
{
  uint_radix(2, Radix::HEX).parse(stream)
}

在我看来,它看起来像是“绑定在单元类型(又名空元组)上”,但我无法理解。单元类型默认不会实现所有特征,对吗?不幸的是,官方文档太模糊,不够完整(同时过于冗长),我在其中找不到任何相关内容。

原始 RFC 的 forwhere子句也提到了这种语法,但没有适当的解释:
https://rust-lang.github.io/rfcs/0135-where.html#alternatives

fn increment<T>(c: T) -> T
    where () : Add<int,T,T>
{
    1 + c
}

但除此之外,我知道不仅可以在特征泛型中指定此类界限。
那么它是什么,何时使用,为什么需要它以及它解决了哪些问题?

generics
  • 2 2 个回答
  • 791 Views

2 个回答

  • Voted
  1. Best Answer
    Timsib Adnap
    2024-11-25T13:17:04+08:002024-11-25T13:17:04+08:00

    在代码片段中,where子句用于缩小通用约束。不是定义所有约束,(): IntRadixParse<Stream, Context, u8>而是使用,这意味着无论类型Stream和Context类型是什么,它们都必须遵循的约束IntRadixParse。

    特征IntRadixParse是

    pub trait IntRadixParse<Stream, Context, Token: 'static> = where
      Stream: Streaming,
      <Stream as Streaming>::Item: Into<u8>,
      Token: CheckedAdd + CheckedMul + CheckedSub + Zero + Copy + Debug,
      Context: Contexting<IntRadixAtom<Token>>,
      Context: Contexting<BaseAtom<u8>>,
      Context: Contexting<CoreAtom<Stream>>,
      Context: Contexting<UtilsAtom<Stream>>,
      u8: AsPrimitive<Token>;
    

    注意:它使用特征别名不稳定功能

    因此,要编写没有奇怪的单位约束语法的函数,它将是这样的

    fn hex_primary<Stream, Context>(stream: Stream) -> Parsed<u8, Stream, Context>
    where
      Stream: Streaming,
      <Stream as Streaming>::Item: Into<u8>,
      Context: Contexting<IntRadixAtom<u8>>,
      Context: Contexting<BaseAtom<u8>>,
      Context: Contexting<CoreAtom<Stream>>,
      Context: Contexting<UtilsAtom<Stream>>,
    {
      uint_radix(2, Radix::HEX).parse(stream)
    }
    

    注意:函数中Token被替换为u8

    另一个例子:

    #![feature(trait_alias)]
    
    trait A<T> = where T: B; // Similar to `IntRadixParse` which
                             // shows that T should implement B
    
    /// trait B with a method a
    trait B {
        fn a(self);
    }
    
    /// implemented for unit
    impl B for () {
        fn a(self) {}
    }
    
    fn a<T>(a: T) where (): A<T> {
        a.a() // T gets inferred to have implemented B and `a()` can be called
    }
    
    fn main() {}
    
    • 6
  2. cafce25
    2024-11-25T19:14:45+08:002024-11-25T19:14:45+08:00

    (): IntRadixParse<Stream, Context, u8>确实是对单位类型的限制。它之所以有效,是因为特征别名1定义如下:

    pub trait IntRadixParse<Stream, Context, Token: 'static> = where
        …; // where bounds omitted for brevity
    

    请特别注意之前缺失的特征where,没有特征,因此在条件成立的情况下,这是没有任何特征的别名。

    每种类型都满足“实现一组空的特征”,因此编译器唯一需要证明的就是边界。简而言之,因为Self没有被引用,也没有特征需要它满足,所以()你可以在那里写任何类型而不是 unit。当类型无关紧要时,Rust 程序员经常使用 unit。

    这使得特征别名对于缩写一堆界限很有用,如Timsib Adnap 的答案中解释的那样


    1. 特征别名不稳定
    • 6

相关问题

  • Rust 无法推断 Fn 类型,其中 Option<Fn> 为 None [重复]

  • 如何在 Rust 中传递一个以迭代器作为函数参数的函数?

  • Rust Specs Crate 系统中的通用组件

  • 将一种泛型类型转换为另一种泛型类型

  • 有没有办法扩展依赖于 F# 中的 K 和 V 的泛型类型 IStore<ValueTuple<K, V>> ?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve