【libm】2整數接口(int_traits.rs)

一、源碼

int_traits.rs文件定義了兩個核心 trait MinInt 和 Int,為整數類型提供統一的抽象接口,并通過宏為所有原生整數類型(i8 ~ i128/u8 ~ u128)實現這些 trait。

use core::{cmp, fmt, ops};/// Minimal integer implementations needed on all integer types, including wide integers.
pub trait MinInt:Copy+ fmt::Debug+ ops::BitOr<Output = Self>+ ops::Not<Output = Self>+ ops::Shl<u32, Output = Self>
{/// Type with the same width but other signednesstype OtherSign: MinInt;/// Unsigned version of Selftype Unsigned: MinInt;/// If `Self` is a signed integerconst SIGNED: bool;/// The bitwidth of the int typeconst BITS: u32;const ZERO: Self;const ONE: Self;const MIN: Self;const MAX: Self;
}/// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated
/// types).
pub type OtherSign<I> = <I as MinInt>::OtherSign;/// Trait for some basic operations on integers
#[allow(dead_code)]
pub trait Int:MinInt+ fmt::Display+ fmt::Binary+ fmt::LowerHex+ PartialEq+ PartialOrd+ ops::AddAssign+ ops::SubAssign+ ops::BitAndAssign+ ops::BitOrAssign+ ops::BitXorAssign+ ops::ShlAssign<i32>+ ops::ShlAssign<u32>+ ops::ShrAssign<u32>+ ops::ShrAssign<i32>+ ops::Add<Output = Self>+ ops::Sub<Output = Self>+ ops::Mul<Output = Self>+ ops::Div<Output = Self>+ ops::Shl<i32, Output = Self>+ ops::Shl<u32, Output = Self>+ ops::Shr<i32, Output = Self>+ ops::Shr<u32, Output = Self>+ ops::BitXor<Output = Self>+ ops::BitAnd<Output = Self>+ cmp::Ord+ From<bool>+ CastFrom<i32>+ CastFrom<u16>+ CastFrom<u32>+ CastFrom<u8>+ CastFrom<usize>+ CastInto<i32>+ CastInto<u16>+ CastInto<u32>+ CastInto<u8>+ CastInto<usize>
{fn signed(self) -> OtherSign<Self::Unsigned>;fn unsigned(self) -> Self::Unsigned;fn from_unsigned(unsigned: Self::Unsigned) -> Self;fn abs(self) -> Self;fn from_bool(b: bool) -> Self;/// Prevents the need for excessive conversions between signed and unsignedfn logical_shr(self, other: u32) -> Self;/// Absolute difference between two integers.fn abs_diff(self, other: Self) -> Self::Unsigned;// copied from primitive integers, but put in a traitfn is_zero(self) -> bool;fn checked_add(self, other: Self) -> Option<Self>;fn checked_sub(self, other: Self) -> Option<Self>;fn wrapping_neg(self) -> Self;fn wrapping_add(self, other: Self) -> Self;fn wrapping_mul(self, other: Self) -> Self;fn wrapping_sub(self, other: Self) -> Self;fn wrapping_shl(self, other: u32) -> Self;fn wrapping_shr(self, other: u32) -> Self;fn rotate_left(self, other: u32) -> Self;fn overflowing_add(self, other: Self) -> (Self, bool);fn overflowing_sub(self, other: Self) -> (Self, bool);fn leading_zeros(self) -> u32;fn ilog2(self) -> u32;
}macro_rules! int_impl_common {($ty:ty) => {fn from_bool(b: bool) -> Self {b as $ty}fn logical_shr(self, other: u32) -> Self {Self::from_unsigned(self.unsigned().wrapping_shr(other))}fn is_zero(self) -> bool {self == Self::ZERO}fn checked_add(self, other: Self) -> Option<Self> {self.checked_add(other)}fn checked_sub(self, other: Self) -> Option<Self> {self.checked_sub(other)}fn wrapping_neg(self) -> Self {<Self>::wrapping_neg(self)}fn wrapping_add(self, other: Self) -> Self {<Self>::wrapping_add(self, other)}fn wrapping_mul(self, other: Self) -> Self {<Self>::wrapping_mul(self, other)}fn wrapping_sub(self, other: Self) -> Self {<Self>::wrapping_sub(self, other)}fn wrapping_shl(self, other: u32) -> Self {<Self>::wrapping_shl(self, other)}fn wrapping_shr(self, other: u32) -> Self {<Self>::wrapping_shr(self, other)}fn rotate_left(self, other: u32) -> Self {<Self>::rotate_left(self, other)}fn overflowing_add(self, other: Self) -> (Self, bool) {<Self>::overflowing_add(self, other)}fn overflowing_sub(self, other: Self) -> (Self, bool) {<Self>::overflowing_sub(self, other)}fn leading_zeros(self) -> u32 {<Self>::leading_zeros(self)}fn ilog2(self) -> u32 {// On our older MSRV, this resolves to the trait method. Which won't actually work,// but this is only called behind other gates.#[allow(clippy::incompatible_msrv)]<Self>::ilog2(self)}};
}macro_rules! int_impl {($ity:ty, $uty:ty) => {impl MinInt for $uty {type OtherSign = $ity;type Unsigned = $uty;const BITS: u32 = <Self as MinInt>::ZERO.count_zeros();const SIGNED: bool = Self::MIN != Self::ZERO;const ZERO: Self = 0;const ONE: Self = 1;const MIN: Self = <Self>::MIN;const MAX: Self = <Self>::MAX;}impl Int for $uty {fn signed(self) -> $ity {self as $ity}fn unsigned(self) -> Self {self}fn abs(self) -> Self {unimplemented!()}// It makes writing macros easier if this is implemented for both signed and unsigned#[allow(clippy::wrong_self_convention)]fn from_unsigned(me: $uty) -> Self {me}fn abs_diff(self, other: Self) -> Self {self.abs_diff(other)}int_impl_common!($uty);}impl MinInt for $ity {type OtherSign = $uty;type Unsigned = $uty;const BITS: u32 = <Self as MinInt>::ZERO.count_zeros();const SIGNED: bool = Self::MIN != Self::ZERO;const ZERO: Self = 0;const ONE: Self = 1;const MIN: Self = <Self>::MIN;const MAX: Self = <Self>::MAX;}impl Int for $ity {fn signed(self) -> Self {self}fn unsigned(self) -> $uty {self as $uty}fn abs(self) -> Self {self.abs()}fn from_unsigned(me: $uty) -> Self {me as $ity}fn abs_diff(self, other: Self) -> $uty {self.abs_diff(other)}int_impl_common!($ity);}};
}int_impl!(isize, usize);
int_impl!(i8, u8);
int_impl!(i16, u16);
int_impl!(i32, u32);
int_impl!(i64, u64);
int_impl!(i128, u128);/// Trait for integers twice the bit width of another integer. This is implemented for all
/// primitives except for `u8`, because there is not a smaller primitive.
pub trait DInt: MinInt {/// Integer that is half the bit width of the integer this trait is implemented fortype H: HInt<D = Self>;/// Returns the low half of `self`fn lo(self) -> Self::H;/// Returns the high half of `self`fn hi(self) -> Self::H;/// Returns the low and high halves of `self` as a tuplefn lo_hi(self) -> (Self::H, Self::H) {(self.lo(), self.hi())}/// Constructs an integer using lower and higher half parts#[allow(unused)]fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self {lo.zero_widen() | hi.widen_hi()}
}/// Trait for integers half the bit width of another integer. This is implemented for all
/// primitives except for `u128`, because it there is not a larger primitive.
pub trait HInt: Int {/// Integer that is double the bit width of the integer this trait is implemented fortype D: DInt<H = Self> + MinInt;// NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for// unknown reasons this can cause infinite recursion when optimizations are disabled. See// <https://github.com/rust-lang/compiler-builtins/pull/707> for context./// Widens (using default extension) the integer to have double bit widthfn widen(self) -> Self::D;/// Widens (zero extension only) the integer to have double bit width. This is needed to get/// around problems with associated type bounds (such as `Int<Othersign: DInt>`) being unstablefn zero_widen(self) -> Self::D;/// Widens the integer to have double bit width and shifts the integer into the higher bits#[allow(unused)]fn widen_hi(self) -> Self::D;/// Widening multiplication with zero widening. This cannot overflow.fn zero_widen_mul(self, rhs: Self) -> Self::D;/// Widening multiplication. This cannot overflow.fn widen_mul(self, rhs: Self) -> Self::D;
}macro_rules! impl_d_int {($($X:ident $D:ident),*) => {$(impl DInt for $D {type H = $X;fn lo(self) -> Self::H {self as $X}fn hi(self) -> Self::H {(self >> <$X as MinInt>::BITS) as $X}})*};
}macro_rules! impl_h_int {($($H:ident $uH:ident $X:ident),*) => {$(impl HInt for $H {type D = $X;fn widen(self) -> Self::D {self as $X}fn zero_widen(self) -> Self::D {(self as $uH) as $X}fn zero_widen_mul(self, rhs: Self) -> Self::D {self.zero_widen().wrapping_mul(rhs.zero_widen())}fn widen_mul(self, rhs: Self) -> Self::D {self.widen().wrapping_mul(rhs.widen())}fn widen_hi(self) -> Self::D {(self as $X) << <Self as MinInt>::BITS}})*};
}impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128);
impl_h_int!(u8 u8 u16,u16 u16 u32,u32 u32 u64,u64 u64 u128,i8 u8 i16,i16 u16 i32,i32 u32 i64,i64 u64 i128
);/// Trait to express (possibly lossy) casting of integers
pub trait CastInto<T: Copy>: Copy {/// By default, casts should be exact.fn cast(self) -> T;/// Call for casts that are expected to truncate.fn cast_lossy(self) -> T;
}pub trait CastFrom<T: Copy>: Copy {/// By default, casts should be exact.fn cast_from(value: T) -> Self;/// Call for casts that are expected to truncate.fn cast_from_lossy(value: T) -> Self;
}impl<T: Copy, U: CastInto<T> + Copy> CastFrom<U> for T {fn cast_from(value: U) -> Self {value.cast()}fn cast_from_lossy(value: U) -> Self {value.cast_lossy()}
}macro_rules! cast_into {($ty:ty) => {cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128);};($ty:ty; $($into:ty),*) => {$(impl CastInto<$into> for $ty {fn cast(self) -> $into {// All we can really do to enforce casting rules is check the rules when in// debug mode.#[cfg(not(feature = "compiler-builtins"))]debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}");self as $into}fn cast_lossy(self) -> $into {self as $into}})*};
}macro_rules! cast_into_float {($ty:ty) => {#[cfg(f16_enabled)]cast_into_float!($ty; f16);cast_into_float!($ty; f32, f64);#[cfg(f128_enabled)]cast_into_float!($ty; f128);};($ty:ty; $($into:ty),*) => {$(impl CastInto<$into> for $ty {fn cast(self) -> $into {#[cfg(not(feature = "compiler-builtins"))]debug_assert_eq!(self as $into as $ty, self, "inexact float cast");self as $into}fn cast_lossy(self) -> $into {self as $into}})*};
}cast_into!(usize);
cast_into!(isize);
cast_into!(u8);
cast_into!(i8);
cast_into!(u16);
cast_into!(i16);
cast_into!(u32);
cast_into!(i32);
cast_into!(u64);
cast_into!(i64);
cast_into!(u128);
cast_into!(i128);cast_into_float!(i8);
cast_into_float!(i16);
cast_into_float!(i32);
cast_into_float!(i64);
cast_into_float!(i128);
  1. 核心 Trait:MinInt
    定義整數類型的最小通用操作集合:
pub trait MinInt: Copy + Debug + BitOr + Not + Shl<u32> {type OtherSign: MinInt;  // 同寬度的相反符號類型(如 `i32` 的 `OtherSign` 是 `u32`)type Unsigned: MinInt;   // 無符號版本const SIGNED: bool;      // 是否為有符號整數const BITS: u32;         // 位數(如 `i32` 是 32)const ZERO: Self;        // 0 值const ONE: Self;         // 1 值const MIN: Self;         // 最小值const MAX: Self;         // 最大值
}
  1. 擴展 Trait:Int
    在 MinInt 基礎上擴展更多操作:
pub trait Int: MinInt + Display + Binary + AddAssign + ... {fn signed(self) -> OtherSign<Self::Unsigned>;  // 轉為有符號類型fn unsigned(self) -> Self::Unsigned;           // 轉為無符號類型fn abs(self) -> Self;                          // 絕對值// 位操作fn logical_shr(self, other: u32) -> Self;      // 邏輯右移(高位補 0)fn rotate_left(self, other: u32) -> Self;      // 循環左移// 溢出安全運算fn wrapping_add(self, other: Self) -> Self;fn checked_mul(self, other: Self) -> Option<Self>;// 工具方法fn leading_zeros(self) -> u32;fn ilog2(self) -> u32;
}
  1. 宏實現
    通過宏 int_impl! 為所有原生整數類型實現 MinInt 和 Int:
int_impl!(i32, u32);  // 為 i32/u32 生成實現

宏展開后:

  • 為 u32 實現 MinInt,關聯 OtherSign = i32。

  • 為 i32 實現 MinInt,關聯 OtherSign = u32。

  • 實現所有 Int 方法(委托給原生整數的方法,如 u32::wrapping_add)。

  1. 寬/窄整數 Trait
    DInt(雙寬度整數)
pub trait DInt: MinInt {type H: HInt<D = Self>;  // 半寬度類型(如 `u64` 的 `H` 是 `u32`)fn lo(self) -> Self::H;   // 取低半部分fn hi(self) -> Self::H;   // 取高半部分fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self;  // 合并高低部分
}

HInt(半寬度整數)

pub trait HInt: Int {type D: DInt<H = Self>;  // 雙寬度類型(如 `u32` 的 `D` 是 `u64`)fn widen(self) -> Self::D;       // 符號擴展fn zero_widen(self) -> Self::D;  // 零擴展fn widen_mul(self, rhs: Self) -> Self::D;  // 擴展乘法
}

宏實現

impl_d_int!(u32 u64);  // 為 u64 實現 DInt,關聯 H = u32
impl_h_int!(u32 u32 u64);  // 為 u32 實現 HInt,關聯 D = u64
  1. 類型轉換 Trait
    CastInto/CastFrom
    提供安全的類型轉換接口:
pub trait CastInto<T: Copy>: Copy {fn cast(self) -> T;          // 精確轉換(失敗時 debug 斷言)fn cast_lossy(self) -> T;    // 允許截斷
}// 為所有整數實現 CastInto
cast_into!(u32; u8, u16, u64);  // u32 可轉換為 u8/u16/u64

二、設計亮點

  1. 統一抽象:通過 trait 為所有整數類型提供一致接口。

  2. 零成本:宏展開后直接調用原生整數操作,無運行時開銷。

  3. 類型安全:

  • 嚴格區分有/無符號類型(通過 OtherSign)。

  • 轉換方法提供編譯時檢查。

  1. 擴展性:支持自定義整數類型實現這些 trait。

###三、使用示例

let x: u32 = 42;
let y: i32 = x.signed();  // 轉為有符號
let z: u64 = x.zero_widen();  // 零擴展為 u64let (lo, hi) = 0x12345678u32.lo_hi();  // 拆分為低 16 位和高 16 位

三、總結

這段代碼是數學庫的基礎設施,通過 trait 和宏實現了:

  • 整數類型的通用操作抽象。

  • 安全且高效的類型轉換。

  • 寬/窄整數的互操作。
    為上層算法(如浮點數解析、大數運算)提供了類型安全的底層支持。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81762.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81762.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81762.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

WebSocket實戰經驗

WebSocket實戰經驗詳解 WebSocket基礎概念 #mermaid-svg-sdkZP4UrWBpk2Hco {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-sdkZP4UrWBpk2Hco .error-icon{fill:#552222;}#mermaid-svg-sdkZP4UrWBpk2Hco .error-tex…

【C/C++】MQTT

文章目錄 MQTT 協議1 基本概念2 核心特性3 核心組件4 C 簡易實現&#xff08;基于 Paho MQTT 庫&#xff09;環境準備示例代碼 不同mqtt對比關鍵差異說明 MQTT 協議 1 基本概念 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一種輕量級的發布/訂閱模式…

《Java 高并發程序設計》筆記

&#x1f4a1; 根據 遺忘曲線&#xff1a;如果沒有記錄和回顧&#xff0c;6天后便會忘記75%的內容 讀書筆記正是幫助你記錄和回顧的工具&#xff0c;不必拘泥于形式&#xff0c;其核心是&#xff1a;記錄、翻看、思考 ::: 書名Java 高并發程序設計作者葛一鳴、郭超狀態已讀完簡…

Fine Structure-Aware Sampling(AAAI 2024)論文筆記和啟發

文章目錄 本文解決的問題本文提出的方法以及啟發 本文解決的問題 傳統的基于Pifu的人體三維重建一般通過采樣來進行學習。一般選擇的采樣方法是空間采樣&#xff0c;具體是在surface的表面隨機位移進行樣本的生成。這里的采樣是同時要在XYZ三個方向上進行。所以這導致了一個問…

【AI面試準備】性能測試與AI模型結合應用指南

面試題&#xff1a; 性能測試&#xff1a;AI模型預測系統瓶頸&#xff08;如LoadRunnerAI模塊&#xff09;。 性能測試與AI模型預測系統瓶頸的結合是當前軟件工程和運維領域的重要趨勢&#xff0c;能夠顯著提升系統優化效率和問題預測能力。以下從核心概念、技術實現、快速掌握…

Spring MVC 與 FreeMarker 整合

以下是 Spring MVC 與 FreeMarker 整合的詳細步驟&#xff0c;包含配置和代碼示例&#xff1a; 1. 添加依賴 在 pom.xml 中引入 Spring MVC 和 FreeMarker 的依賴&#xff08;以 Maven 為例&#xff09;&#xff1a; <!-- Spring Web MVC --> <dependency><gr…

Redis分布式鎖使用以及對接支付寶,paypal,strip跨境支付

本章重點在于如何使用redis的分布式鎖來鎖定庫存。減少超賣&#xff0c;同時也對接了支付寶&#xff0c;paypal&#xff0c;strip跨境支付 第一步先建立一個商品表 CREATE TABLE sys_product (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主鍵,code varchar(60) DEFAUL…

使用frpc鏈接內網的mysql

以下是配置 frpc 連接內網 MySQL 服務的詳細步驟&#xff1a; 1. 準備工作 frps 服務器&#xff1a;已部署在公網 IP 11.117.11.245&#xff0c;假設 frps 的默認端口為 7000。 內網 MySQL 服務&#xff1a;運行在內網機器的 3306 端口。 目標&#xff1a;通過公網 IP 11.117…

2025信息安全網絡安全意識培訓資料匯編(24份)

最新整理&#xff1a;2025信息安全網絡安全意識培訓資料匯編&#xff0c;共24份資料&#xff0c;供學習參考。 互聯網信息安全意識培訓.pptx100個網絡安全風險防范知識.pptx亞信信息安全意識培訓.pptx網絡安全法規及意識培訓.pptx網絡安全意識與案例分析.pptx綠盟-安全意識培訓…

JAVA:使用 XStream 實現對象與XML轉換的技術指南

1、簡述 XStream 是一個簡單便捷的 Java 庫,用于對象與 XML 的相互轉換。其主要特點是: 易于使用:無需復雜的配置即可直接使用。支持自定義:可以靈活地定制對象的序列化和反序列化規則。強大的功能:支持注解、自定義轉換器等。本文將詳細介紹 XStream 的基本使用方法,并…

VITA STANDARDS LIST,VITA 標準清單下載

VITA STANDARDS LIST&#xff0c;VITA 標準清單下載 DesignationTitleAbstractStatusVMEbus Handbook, 4th EditionA users guide to the VME, VME64 and VME64x bus specifications - features over 70 product photos and over 160 circuit diagrams, tables and graphs. The…

Assetto Corsa 神力科莎 [DLC 解鎖] [Steam] [Windows]

Assetto Corsa 神力科莎 [DLC 解鎖] [Steam] [Windows] 需要有游戲正版基礎本體&#xff0c;安裝路徑不能帶有中文&#xff0c;或其它非常規拉丁字符&#xff1b; DLC 版本 至最新全部 DLC 后續可能無法及時更新文章&#xff0c;具體最新版本見下載文件說明 DLC 解鎖列表&…

【Java idea配置】

IntelliJ IDEA創建類時自動生成注釋 /** * program: ${PROJECT_NAME} * * since: jdk1.8 * * description: ${description} * * author: ${USER} * * create: ${YEAR}-${MONTH}-${DAY} ${HOUR}:${MINUTE} **/自動導入和自動移除無用導入 idea彩色日志不生效 調試日志輸出 在…

計算方法實驗六 數值積分

【實驗性質】綜合性實驗。 【實驗目的】理解插值型積分法&#xff1b;掌握復化積分法算法。 【實驗內容】 1對 &#xff0c;用復化梯形積分和變步長梯形積分求值&#xff08;截斷誤差不超過&#xff09;。 【理論基礎】 積分在工程中有重要的應用&#xff0c;數值積分…

Webug4.0靶場通關筆記11- 第15關任意文件下載與第16關MySQL配置文件下載

目錄 一、文件下載 二、第15關 任意文件下載 1.打開靶場 2.源碼分析 3.滲透實戰 三、第16關 MySQL配置文件下載 1.打開靶場 2.源碼分析 3.滲透實戰 &#xff08;1&#xff09;Windows系統 &#xff08;2&#xff09;Linux系統 四、滲透防御 一、文件下載 本文通過…

小土堆pytorch--tensorboard的使用

小土堆pytorch--tensorboard的使用 小土堆pytorch--tensorboard的使用0.介紹1.使用tensorboard繪制 y x 等簡單函數1.1 相應的代碼1.2 對上述代碼的解釋1.3 可能遇到的問題1.3.1 問題1.3.2 解決方法 2.使用tensorboard加載數據集中的圖片2.1 相應代碼2.2 對上述代碼的解釋2.2.…

大模型(LLMs)RAG 版面分析——文本分塊面

大模型&#xff08;LLMs&#xff09;RAG 版面分析——文本分塊面 一、為什么需要對文本分塊&#xff1f; 二、能不能介紹一下常見的文本分塊方法&#xff1f; 2.1 一般的文本分塊方法 2.2 正則拆分的文本分塊方法 2.3 Spacy Text Splitter 方法 2.4 基于 langchain 的 Cha…

解構區塊鏈身份認證:從ID到零知識證明的實戰指南

引言 在數字經濟高速發展的今天&#xff0c;數字身份已成為個人與數字世界交互的核心憑證。傳統中心化身份系統存在數據孤島、隱私泄露、單點故障等痛點&#xff0c;而區塊鏈技術憑借??去中心化、不可篡改、可追溯??的特性&#xff0c;為數字身份驗證提供了革命性解決方案…

c#數據結構 線性表篇 非常用線性集合總結

本人能力有限,使用了一些Ai的結論,如有不足還請斧正 目錄 1.HashSet <> Dictionary 2.SortedSet <>提供升序方法的List 3.ArrayList<>List 4.BitArray <> Bit[] array 5.StringCollection <>List 6.StringDictionary<>Dictionary 1…

爬蟲管理平臺-最新版本發布

TaskPyro 是什么&#xff1f; TaskPyro 是一個輕量級的 Python 任務調度平臺&#xff0c;專注于提供簡單易用的任務管理和爬蟲調度解決方案。它能夠幫助您輕松管理和調度 Python 任務&#xff0c;特別適合需要定時執行的爬蟲任務和數據處理任務。 官方文檔&#xff1a;https:/…