5 长度和距离计算模块(length.rs)

这段代码定义了一个泛型结构体 Length<T, Unit>,用于表示一维长度,其中 T 表示长度的数值类型,而 Unit 是一个编译时检查单位一致性的占位符类型,不会用于运行时表示长度的值。这个设计允许开发者在编译阶段确保不同单位之间的长度值在使用前进行了显式的单位转换。

一、length.rs文件源码

//! 用计量单位标记的一维长度。

use crate::approxeq::ApproxEq;
use crate::approxord::{max, min};
use crate::num::Zero;
use crate::scale::Scale;

use crate::num::One;
#[cfg(feature = "bytemuck")]
use bytemuck::{Pod, Zeroable};
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::iter::Sum;
use core::marker::PhantomData;
use core::ops::{Add, Div, Mul, Neg, Sub};
use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
use num_traits::{NumCast, Saturating};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

/*
一维距离,其值由“T”表示,测量单位为“Unit”。 
“T”可以是任何数字类型,例如像“u64”或“f32”这样的基元类型。 
“Unit”不用于表示“Length”值。它仅在编译时使用,以确保用一个单位存储的“Length”在用于需要不同单位的表达式之前被显式转换。它可能是一个没有值的类型,例如空枚举。 
您可以将“Length”乘以“Scale”,将其从一个单位转换为另一个单位。请参阅[`Scale`]结构体。
*/
#[repr(C)]
pub struct Length<T, Unit>(pub T, #[doc(hidden)] pub PhantomData<Unit>);

impl<T: Clone, U> Clone for Length<T, U> {
    fn clone(&self) -> Self {
        Length(self.0.clone(), PhantomData)
    }
}

impl<T: Copy, U> Copy for Length<T, U> {}

#[cfg(feature = "serde")]
impl<'de, T, U> Deserialize<'de> for Length<T, U> where T: Deserialize<'de>,{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,{
        Ok(Length(Deserialize::deserialize(deserializer)?, PhantomData))
    }
}

#[cfg(feature = "serde")]
impl<T, U> Serialize for Length<T, U> where T: Serialize,{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,{
        self.0.serialize(serializer)
    }
}

#[cfg(feature = "arbitrary")]
impl<'a, T, U> arbitrary::Arbitrary<'a> for Length<T, U>
where
    T: arbitrary::Arbitrary<'a>,
{
    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
        Ok(Length(arbitrary::Arbitrary::arbitrary(u)?, PhantomData))
    }
}

#[cfg(feature = "bytemuck")]
unsafe impl<T: Zeroable, U> Zeroable for Length<T, U> {}

#[cfg(feature = "bytemuck")]
unsafe impl<T: Pod, U: 'static> Pod for Length<T, U> {}

impl<T, U> Length<T, U> {
    /// 将值与度量单位相关联。
    #[inline]
    pub const fn new(x: T) -> Self {
        Length(x, PhantomData)
    }
}

impl<T: Clone, U> Length<T, U> {
    /// 从类中提取基值
    pub fn get(self) -> T {
        self.0
    }

    /// Cast the unit
    #[inline]
    pub fn cast_unit<V>(self) -> Length<T, V> {
        Length::new(self.0)
    }

    /// Linearly interpolate between this length and another length.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::default::Length;
    ///
    /// let from = Length::new(0.0);
    /// let to = Length::new(8.0);
    ///
    /// assert_eq!(from.lerp(to, -1.0), Length::new(-8.0));
    /// assert_eq!(from.lerp(to,  0.0), Length::new( 0.0));
    /// assert_eq!(from.lerp(to,  0.5), Length::new( 4.0));
    /// assert_eq!(from.lerp(to,  1.0), Length::new( 8.0));
    /// assert_eq!(from.lerp(to,  2.0), Length::new(16.0));
    /// ```
    #[inline]
    pub fn lerp(self, other: Self, t: T) -> Self
    where
        T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
    {
        let one_t = T::one() - t.clone();
        Length::new(one_t * self.0.clone() + t * other.0)
    }
}

impl<T: PartialOrd, U> Length<T, U> {
    /// Returns minimum between this length and another length.
    #[inline]
    pub fn min(self, other: Self) -> Self {
        min(self, other)
    }

    /// Returns maximum between this length and another length.
    #[inline]
    pub fn max(self, other: Self) -> Self {
        max(self, other)
    }
}

impl<T: NumCast + Clone, U> Length<T, U> {
    /// Cast from one numeric representation to another, preserving the units.
    #[inline]
    pub fn cast<NewT: NumCast>(self) -> Length<NewT, U> {
        self.try_cast().unwrap()
    }

    /// Fallible cast from one numeric representation to another, preserving the units.
    pub fn try_cast<NewT: NumCast>(self) -> Option<Length<NewT, U>> {
        NumCast::from(self.0).map(Length::new)
    }
}

impl<T: fmt::Debug, U> fmt::Debug for Length<T, U> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<T: Default, U> Default for Length<T, U> {
    #[inline]
    fn default() -> Self {
        Length::new(Default::default())
    }
}

impl<T: Hash, U> Hash for Length<T, U> {
    fn hash<H: Hasher>(&self, h: &mut H) {
        self.0.hash(h);
    }
}

// length + length
impl<T: Add, U> Add for Length<T, U> {
    type Output = Length<T::Output, U>;

    fn add(self, other: Self) -> Self::Output {
        Length::new(self.0 + other.0)
    }
}

// length + &length
impl<T: Add + Copy, U> Add<&Self> for Length<T, U> {
    type Output = Length<T::Output, U>;

    fn add(self, other: &Self) -> Self::Output {
        Length::new(self.0 + other.0)
    }
}

// length_iter.copied().sum()
impl<T: Add<Output = T> + Zero, U> Sum for Length<T, U> {
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        iter.fold(Self::zero(), Add::add)
    }
}

// length_iter.sum()
impl<'a, T: 'a + Add<Output = T> + Copy + Zero, U: 'a> Sum<&'a Self> for Length<T, U> {
    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
        iter.fold(Self::zero(), Add::add)
    }
}

// length += length
impl<T: AddAssign, U> AddAssign for Length<T, U> {
    fn add_assign(&mut self, other: Self) {
        self.0 += other.0;
    }
}

// length - length
impl<T: Sub, U> Sub for Length<T, U> {
    type Output = Length<T::Output, U>;

    fn sub(self, other: Length<T, U>) -> Self::Output {
        Length::new(self.0 - other.0)
    }
}

// length -= length
impl<T: SubAssign, U> SubAssign for Length<T, U> {
    fn sub_assign(&mut self, other: Self) {
        self.0 -= other.0;
    }
}

// Saturating length + length and length - length.
impl<T: Saturating, U> Saturating for Length<T, U> {
    fn saturating_add(self, other: Self) -> Self {
        Length::new(self.0.saturating_add(other.0))
    }

    fn saturating_sub(self, other: Self) -> Self {
        Length::new(self.0.saturating_sub(other.0))
    }
}

// length / length
impl<Src, Dst, T: Div> Div<Length<T, Src>> for Length<T, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn div(self, other: Length<T, Src>) -> Self::Output {
        Scale::new(self.0 / other.0)
    }
}

// length * scalar
impl<T: Mul, U> Mul<T> for Length<T, U> {
    type Output = Length<T::Output, U>;

    #[inline]
    fn mul(self, scale: T) -> Self::Output {
        Length::new(self.0 * scale)
    }
}

// length *= scalar
impl<T: Copy + Mul<T, Output = T>, U> MulAssign<T> for Length<T, U> {
    #[inline]
    fn mul_assign(&mut self, scale: T) {
        *self = *self * scale;
    }
}

// length / scalar
impl<T: Div, U> Div<T> for Length<T, U> {
    type Output = Length<T::Output, U>;

    #[inline]
    fn div(self, scale: T) -> Self::Output {
        Length::new(self.0 / scale)
    }
}

// length /= scalar
impl<T: Copy + Div<T, Output = T>, U> DivAssign<T> for Length<T, U> {
    #[inline]
    fn div_assign(&mut self, scale: T) {
        *self = *self / scale;
    }
}

// length * scaleFactor
impl<Src, Dst, T: Mul> Mul<Scale<T, Src, Dst>> for Length<T, Src> {
    type Output = Length<T::Output, Dst>;

    #[inline]
    fn mul(self, scale: Scale<T, Src, Dst>) -> Self::Output {
        Length::new(self.0 * scale.0)
    }
}

// length / scaleFactor
impl<Src, Dst, T: Div> Div<Scale<T, Src, Dst>> for Length<T, Dst> {
    type Output = Length<T::Output, Src>;

    #[inline]
    fn div(self, scale: Scale<T, Src, Dst>) -> Self::Output {
        Length::new(self.0 / scale.0)
    }
}

// -length
impl<U, T: Neg> Neg for Length<T, U> {
    type Output = Length<T::Output, U>;

    #[inline]
    fn neg(self) -> Self::Output {
        Length::new(-self.0)
    }
}

impl<T: PartialEq, U> PartialEq for Length<T, U> {
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }
}

impl<T: PartialOrd, U> PartialOrd for Length<T, U> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T: Eq, U> Eq for Length<T, U> {}

impl<T: Ord, U> Ord for Length<T, U> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T: Zero, U> Zero for Length<T, U> {
    #[inline]
    fn zero() -> Self {
        Length::new(Zero::zero())
    }
}

impl<U, T: ApproxEq<T>> ApproxEq<T> for Length<T, U> {
    #[inline]
    fn approx_epsilon() -> T {
        T::approx_epsilon()
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Length<T, U>, approx_epsilon: &T) -> bool {
        self.0.approx_eq_eps(&other.0, approx_epsilon)
    }
}

#[cfg(test)]
mod tests {
    use super::Length;
    use crate::num::Zero;

    use crate::scale::Scale;
    use core::f32::INFINITY;
    use num_traits::Saturating;

    enum Inch {}
    enum Mm {}
    enum Cm {}
    enum Second {}

    #[cfg(feature = "serde")]
    mod serde {
        use super::*;

        extern crate serde_test;
        use self::serde_test::assert_tokens;
        use self::serde_test::Token;

        #[test]
        fn test_length_serde() {
            let one_cm: Length<f32, Mm> = Length::new(10.0);

            assert_tokens(&one_cm, &[Token::F32(10.0)]);
        }
    }

    #[test]
    fn test_clone() {
        // A cloned Length is a separate length with the state matching the
        // original Length at the point it was cloned.
        let mut variable_length: Length<f32, Inch> = Length::new(12.0);

        let one_foot = variable_length.clone();
        variable_length.0 = 24.0;

        assert_eq!(one_foot.get(), 12.0);
        assert_eq!(variable_length.get(), 24.0);
    }

    #[test]
    fn test_add() {
        let length1: Length<u8, Mm> = Length::new(250);
        let length2: Length<u8, Mm> = Length::new(5);

        assert_eq!((length1 + length2).get(), 255);
        assert_eq!((length1 + &length2).get(), 255);
    }

    #[test]
    fn test_sum() {
        type L = Length<f32, Mm>;
        let lengths = [L::new(1.0), L::new(2.0), L::new(3.0)];

        assert_eq!(lengths.iter().sum::<L>(), L::new(6.0));
    }

    #[test]
    fn test_addassign() {
        let one_cm: Length<f32, Mm> = Length::new(10.0);
        let mut measurement: Length<f32, Mm> = Length::new(5.0);

        measurement += one_cm;

        assert_eq!(measurement.get(), 15.0);
    }

    #[test]
    fn test_sub() {
        let length1: Length<u8, Mm> = Length::new(250);
        let length2: Length<u8, Mm> = Length::new(5);

        let result = length1 - length2;

        assert_eq!(result.get(), 245);
    }

    #[test]
    fn test_subassign() {
        let one_cm: Length<f32, Mm> = Length::new(10.0);
        let mut measurement: Length<f32, Mm> = Length::new(5.0);

        measurement -= one_cm;

        assert_eq!(measurement.get(), -5.0);
    }

    #[test]
    fn test_saturating_add() {
        let length1: Length<u8, Mm> = Length::new(250);
        let length2: Length<u8, Mm> = Length::new(6);

        let result = length1.saturating_add(length2);

        assert_eq!(result.get(), 255);
    }

    #[test]
    fn test_saturating_sub() {
        let length1: Length<u8, Mm> = Length::new(5);
        let length2: Length<u8, Mm> = Length::new(10);

        let result = length1.saturating_sub(length2);

        assert_eq!(result.get(), 0);
    }

    #[test]
    fn test_division_by_length() {
        // Division results in a Scale from denominator units
        // to numerator units.
        let length: Length<f32, Cm> = Length::new(5.0);
        let duration: Length<f32, Second> = Length::new(10.0);

        let result = length / duration;

        let expected: Scale<f32, Second, Cm> = Scale::new(0.5);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_multiplication() {
        let length_mm: Length<f32, Mm> = Length::new(10.0);
        let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);

        let result = length_mm * cm_per_mm;

        let expected: Length<f32, Cm> = Length::new(1.0);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_multiplication_with_scalar() {
        let length_mm: Length<f32, Mm> = Length::new(10.0);

        let result = length_mm * 2.0;

        let expected: Length<f32, Mm> = Length::new(20.0);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_multiplication_assignment() {
        let mut length: Length<f32, Mm> = Length::new(10.0);

        length *= 2.0;

        let expected: Length<f32, Mm> = Length::new(20.0);
        assert_eq!(length, expected);
    }

    #[test]
    fn test_division_by_scalefactor() {
        let length: Length<f32, Cm> = Length::new(5.0);
        let cm_per_second: Scale<f32, Second, Cm> = Scale::new(10.0);

        let result = length / cm_per_second;

        let expected: Length<f32, Second> = Length::new(0.5);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_division_by_scalar() {
        let length: Length<f32, Cm> = Length::new(5.0);

        let result = length / 2.0;

        let expected: Length<f32, Cm> = Length::new(2.5);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_division_assignment() {
        let mut length: Length<f32, Mm> = Length::new(10.0);

        length /= 2.0;

        let expected: Length<f32, Mm> = Length::new(5.0);
        assert_eq!(length, expected);
    }

    #[test]
    fn test_negation() {
        let length: Length<f32, Cm> = Length::new(5.0);

        let result = -length;

        let expected: Length<f32, Cm> = Length::new(-5.0);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_cast() {
        let length_as_i32: Length<i32, Cm> = Length::new(5);

        let result: Length<f32, Cm> = length_as_i32.cast();

        let length_as_f32: Length<f32, Cm> = Length::new(5.0);
        assert_eq!(result, length_as_f32);
    }

    #[test]
    fn test_equality() {
        let length_5_point_0: Length<f32, Cm> = Length::new(5.0);
        let length_5_point_1: Length<f32, Cm> = Length::new(5.1);
        let length_0_point_1: Length<f32, Cm> = Length::new(0.1);

        assert!(length_5_point_0 == length_5_point_1 - length_0_point_1);
        assert!(length_5_point_0 != length_5_point_1);
    }

    #[test]
    fn test_order() {
        let length_5_point_0: Length<f32, Cm> = Length::new(5.0);
        let length_5_point_1: Length<f32, Cm> = Length::new(5.1);
        let length_0_point_1: Length<f32, Cm> = Length::new(0.1);

        assert!(length_5_point_0 < length_5_point_1);
        assert!(length_5_point_0 <= length_5_point_1);
        assert!(length_5_point_0 <= length_5_point_1 - length_0_point_1);
        assert!(length_5_point_1 > length_5_point_0);
        assert!(length_5_point_1 >= length_5_point_0);
        assert!(length_5_point_0 >= length_5_point_1 - length_0_point_1);
    }

    #[test]
    fn test_zero_add() {
        type LengthCm = Length<f32, Cm>;
        let length: LengthCm = Length::new(5.0);

        let result = length - LengthCm::zero();

        assert_eq!(result, length);
    }

    #[test]
    fn test_zero_division() {
        type LengthCm = Length<f32, Cm>;
        let length: LengthCm = Length::new(5.0);
        let length_zero: LengthCm = Length::zero();

        let result = length / length_zero;

        let expected: Scale<f32, Cm, Cm> = Scale::new(INFINITY);
        assert_eq!(result, expected);
    }
}

二、结构体定义

#[repr(C)]
pub struct Length<T, Unit>(pub T, #[doc(hidden)] pub PhantomData<Unit>);
  • #[repr©]:保证结构体在内存中的布局与C语言兼容,通常用于确保与C/C++代码或外部接口的二进制兼容性。
  • PhantomData:一个零大小的类型,用于在编译时携带类型信息,而不会增加结构体的大小。这里用于确保单位的一致性。

三、实现Clone

impl<T: Clone, U> Clone for Length<T, U> {
    fn clone(&self) -> Self {
        Length(self.0.clone(), PhantomData)
    }
}
  • 这段代码实现了Clone trait,允许Length类型的值被克隆。
  • PhantomData的实例化应使用PhantomData::,而不是直接使用PhantomData(虽然Rust编译器通常可以推断)。

四、cast和try_cast方法

impl<T: NumCast + Clone, U> Length<T, U> {
    /// Cast from one numeric representation to another, preserving the units.
    #[inline]
    pub fn cast<NewT: NumCast>(self) -> Length<NewT, U> {
        self.try_cast().unwrap()
    }
    /// Fallible cast from one numeric representation to another, preserving the units.
    pub fn try_cast<NewT: NumCast>(self) -> Option<Length<NewT, U>> {
        NumCast::from(self.0).map(Length::new)
    }
}
  • 这里我们使用了num_traits::NumCast trait来实现数值类型之间的转换。
  • cast方法调用try_cast并解包Option,这意味着如果转换失败,程序将会panic。
  • try_cast方法尝试将Length的数值部分从类型T转换为NewT,如果成功,则使用新的数值和原始的单位类型U创建一个新的Length值。

五、其他trait实现

  • fmt::Debug:为Length实现Debug trait,使得Length值可以格式化输出。
  • Default:为Length实现Default trait,允许使用default()方法创建默认值的Length实例。
  • Hash:为Length实现Hash trait,使得Length值可以被哈希。
  • Length + Length 的加法
  • Length + &Length 的加法
  • Length 迭代器的求和(Sum)实现(针对可复制的情况)
  • &Length 迭代器的求和(Sum)实现
  • Length += Length 的加法
  • 减法实现
  • 比较特性(PartialEq, PartialOrd, Eq, Ord)的实现
  • 零值特性(Zero)的实现
  • 近似相等特性(ApproxEq)的实现
    #六、结束语
    这个结构体不仅提供了数值和单位的泛型表示,还通过实现各种 trait 来支持丰富的操作,如加减、克隆、比较和哈希等。这使得 Length<T, U> 能够与 Rust 标准库中的许多算法和数据结构无缝协作,同时保持了泛型性和类型安全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/962512.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

记录一次,PyQT的报错,多线程Udp失效,使用工具如netstat来检查端口使用情况。

1.问题 报错Exception in thread Thread-1: Traceback (most recent call last): File "threading.py", line 932, in _bootstrap_inner File "threading.py", line 870, in run File "main.py", line 456, in udp_recv IndexError: list…

论文阅读(十):用可分解图模型模拟连锁不平衡

1.论文链接&#xff1a;Modeling Linkage Disequilibrium with Decomposable Graphical Models 摘要&#xff1a; 本章介绍了使用可分解的图形模型&#xff08;DGMs&#xff09;表示遗传数据&#xff0c;或连锁不平衡&#xff08;LD&#xff09;&#xff0c;各种下游应用程序之…

本地部署DeepSeek开源多模态大模型Janus-Pro-7B实操

本地部署DeepSeek开源多模态大模型Janus-Pro-7B实操 Janus-Pro-7B介绍 Janus-Pro-7B 是由 DeepSeek 开发的多模态 AI 模型&#xff0c;它在理解和生成方面取得了显著的进步。这意味着它不仅可以处理文本&#xff0c;还可以处理图像等其他模态的信息。 模型主要特点:Permalink…

从 UTC 日期时间字符串获取 Unix 时间戳:C 和 C++ 中的挑战与解决方案

在编程世界里&#xff0c;从 UTC 日期时间字符串获取 Unix 时间戳&#xff0c;看似简单&#xff0c;实则暗藏玄机。你以为输入一个像 “Fri, 17 Jan 2025 06:07:07” 这样的 UTC 时间&#xff0c;然后轻松得到 1737094027&#xff08;从 1970 年 1 月 1 日 00:00:00 UTC 开始经…

Linux——网络(tcp)

文章目录 目录 文章目录 前言 一、TCP逻辑 1. 面向连接 三次握手&#xff08;建立连接&#xff09; 四次挥手&#xff08;关闭连接&#xff09; 2. 可靠性 3. 流量控制 4. 拥塞控制 5. 基于字节流 6. 全双工通信 7. 状态机 8. TCP头部结构 9. TCP的应用场景 二、编写tcp代码函数…

51单片机(STC89C52)开发:点亮一个小灯

软件安装&#xff1a; 安装开发板CH340驱动。 安装KEILC51开发软件&#xff1a;C51V901.exe。 下载软件&#xff1a;PZ-ISP.exe 创建项目&#xff1a; 新建main.c 将main.c加入至项目中&#xff1a; main.c:点亮一个小灯 #include "reg52.h"sbit LED1P2^0; //P2的…

力扣116. 填充每个节点的下一个右侧节点指针

Problem: 116. 填充每个节点的下一个右侧节点指针 文章目录 题目描述思路复杂度Code 题目描述 思路 遍历思想(利用二叉树的先序遍历) 本题目的难点在于对于不同父节点的邻接问题因此我们可以抽象将两两节点为一组&#xff08;不同父节点的两个孩子节点也抽象为一组&#xff09…

k8s简介,k8s环境搭建

目录 K8s简介环境搭建和准备工作修改主机名&#xff08;所有节点&#xff09;配置静态IP&#xff08;所有节点&#xff09;关闭防火墙和seLinux&#xff0c;清除iptables规则&#xff08;所有节点&#xff09;关闭交换分区&#xff08;所有节点&#xff09;修改/etc/hosts文件&…

苯乙醇苷类化合物的从头生物合成-文献精读108

Complete pathway elucidation of echinacoside in Cistanche tubulosa and de novo biosynthesis of phenylethanoid glycosides 管花肉苁蓉中松果菊苷全生物合成途径解析及苯乙醇苷类化合物的从头生物合成 摘要 松果菊苷&#xff08;ECH&#xff09;是最具代表性的苯乙醇苷…

C++ 新特性实现 ThreadPool

序言 在之前我们实现过线程池&#xff0c;但是非常基础。答题思路就是实现一个安全的队列&#xff0c;再通过 ThreadPool 来管理队列和线程&#xff0c;对外提供一个接口放入需要执行的函数&#xff0c;但是这个函数是无参无返回值的。  参数的问题我们可以使用 bind 来封装&a…

网络攻防实战指北专栏讲解大纲与网络安全法

专栏 本专栏为网络攻防实战指北&#xff0c;大纲如下所示 进度&#xff1a;目前已更完准备篇、HTML基础 计划&#xff1a;所谓基础不牢&#xff0c;地动山摇。所以下一步将持续更新基础篇内容 讲解信息安全时&#xff0c;结合《中华人民共和国网络安全法》&#xff08;以下简…

计算机网络——流量控制

流量控制的基本方法是确保发送方不会以超过接收方处理能力的速度发送数据包。 通常的做法是接收方会向发送方提供某种反馈&#xff0c;如&#xff1a; &#xff08;1&#xff09;停止&等待 在任何时候只有一个数据包在传输&#xff0c;发送方发送一个数据包&#xff0c;…

知识库管理系统助力企业实现知识共享与创新价值的转型之道

内容概要 知识库管理系统&#xff08;KMS&#xff09;作为现代企业知识管理的重要组成部分&#xff0c;其定义涵盖了系统化捕捉、存储、共享和应用知识的过程。这类系统通过集成各种信息来源&#xff0c;不仅为员工提供了一个集中式的知识平台&#xff0c;还以其结构化的方式提…

⼆叉树的存储(上)c++

在前几天写的树&#xff0c;我们已经了解到树的存储&#xff0c;⼆叉树也是树&#xff0c;也是可以⽤vector数组或者链式前向星来存储。仅需在存储的过程中标记谁是左孩⼦&#xff0c;谁是右孩⼦即可。 ⽐如⽤ vector 数组存储时&#xff0c;可以先尾插左孩⼦&#xff0c;再尾…

2025创业思路和方向有哪些?

创业思路和方向是决定创业成功与否的关键因素。以下是一些基于找到的参考内容的创业思路和方向&#xff0c;旨在激发创业灵感&#xff1a; 一、技术创新与融合&#xff1a; 1、智能手机与云电视结合&#xff1a;开发集成智能手机功能的云电视&#xff0c;提供通讯、娱乐一体化体…

研发的护城河到底是什么?

0 你的问题&#xff0c;我知道&#xff01; 和大厂朋友聊天&#xff0c;他感叹原来努力干活&#xff0c;做靠谱研发&#xff0c;积累职场经验&#xff0c;干下来&#xff0c;职业发展一般问题不大。而如今大厂“年轻化”&#xff0c;靠谱再不能为自己续航&#xff0c;企业似乎…

FreeRTOS从入门到精通 第十五章(事件标志组)

参考教程&#xff1a;【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili 一、事件标志组简介 1、概述 &#xff08;1&#xff09;事件标志位是一个“位”&#xff0c;用来表示事件是否发生。 &#xff08;2&#xff09;事件标志组是一组事件标志位的集合&#x…

学习数据结构(5)单向链表的实现

&#xff08;1&#xff09;头部插入 &#xff08;2&#xff09;尾部删除 &#xff08;3&#xff09;头部删除 &#xff08;4&#xff09;查找 &#xff08;5&#xff09;在指定位置之前插入节点 &#xff08;6&#xff09;在指定位置之后插入节点 &#xff08;7&#xff09;删除…

Golang :用Redis构建高效灵活的应用程序

在当前的应用程序开发中&#xff0c;高效的数据存储和检索的必要性已经变得至关重要。Redis是一个快速的、开源的、内存中的数据结构存储&#xff0c;为各种应用场景提供了可靠的解决方案。在这个完整的指南中&#xff0c;我们将学习什么是Redis&#xff0c;通过Docker Compose…

18 大量数据的异步查询方案

在分布式的应用中分库分表大家都已经熟知了。如果我们的程序中需要做一个模糊查询&#xff0c;那就涉及到跨库搜索的情况&#xff0c;这个时候需要看中间件能不能支持跨库求交集的功能。比如mycat就不支持跨库查询&#xff0c;当然现在mycat也渐渐被摒弃了(没有处理笛卡尔交集的…