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>
whereT: 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) -> SelfwhereT: 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 标准库中的许多算法和数据结构无缝协作,同时保持了泛型性和类型安全。
相关文章:
5 长度和距离计算模块(length.rs)
这段代码定义了一个泛型结构体 Length<T, Unit>,用于表示一维长度,其中 T 表示长度的数值类型,而 Unit 是一个编译时检查单位一致性的占位符类型,不会用于运行时表示长度的值。这个设计允许开发者在编译阶段确保不同单位之间…...
ollama改模型的存盘目录解决下载大模型报c:盘空间不足的问题
使用Ollama和Open WebUI快速玩转大模型:简单快捷的尝试各种llm大模型,比如DeepSeek r1,非常简单方便,参见:使用Ollama和Open WebUI快速玩转大模型:简单快捷的尝试各种llm大模型,比如DeepSeek r1…...
OSCP:常见文件传输方法
在渗透测试过程中,文件传输是一个关键环节,涉及不同的协议和工具,本文整理了 Linux 和 Windows 系统下常见的文件传输方法,并提供相应的命令示例。 通用文件传输方式 Base64 编码传输 Base64 可用于跨平台传输文件,…...
B站吴恩达机器学习笔记
机器学习视频地址: 4.5 线性回归中的梯度下降_哔哩哔哩_bilibili 机器学习分类: 1. 有监督学习(Supervised Learning) 在有监督学习中,训练数据包含了输入特征和正确的输出标签,模型通过这些带有标签的…...
Java 性能优化与新特性
Java学习资料 Java学习资料 Java学习资料 一、引言 Java 作为一门广泛应用于企业级开发、移动应用、大数据等多个领域的编程语言,其性能和特性一直是开发者关注的重点。随着软件系统的规模和复杂度不断增加,对 Java 程序性能的要求也越来越高。同时&a…...
【计算机网络】host文件
host文件的主要功能: 域名解析 本地映射:host文件的主要功能是将**域名映射到相应的 IP 地址**。当计算机需要访问一个网站或服务时,它会首先在 host文件中查找该域名对应的 IP 地址。如果在 host文件中找到了匹配的域名和 IP 地址映射&…...
【C语言】在Windows上为可执行文件.exe添加自定义图标
本文详细介绍了在 Windows 环境下,如何为使用 GCC 编译器编译的 C程序 添加自定义图标,从而生成带有图标的 .exe 可执行文件。通过本文的指导,读者可以了解到所需的条件以及具体的操作步骤,使生成的程序更具专业性和个性化。 目录 1. 准备条件2. 具体步骤步骤 1: 准备资源文…...
爬虫基础(五)爬虫基本原理
目录 一、爬虫是什么 二、爬虫过程 (1)获取网页 (2)提取信息 (3)保存数据 三、爬虫可爬的数据 四、爬虫问题 一、爬虫是什么 互联网,后面有个网字,我们可以把它看成一张蜘蛛网…...
力扣【1049. 最后一块石头的重量 II】Java题解(背包问题)
让石头分成重量相同的两堆(尽可能相同),相撞之后剩下的石头就是最小的。进一步转化成容量为重量总喝一半的背包最多可以装多少质量的石头。这样就转化成了背包问题。 最后求结果时,我们所最多能装的时dp[target],那另一…...
FFmpeg rtmp推流直播
文章目录 rtmp协议RTMP协议组成RTMP的握手过程RTMP流的创建RTMP消息格式Chunking(Message 分块) rtmp服务器搭建Nginx服务器配置Nginx服务器 librtmp库编译推流 rtmp协议 RTMP(Real Time Messaging Protocol)是由Adobe公司基于Flash Player播放器对应的…...
WordPress Icegram Express插件Sql注入漏洞复现(CVE-2024-2876)(附脚本)
免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 0x0…...
重构字符串(767)
767. 重构字符串 - 力扣(LeetCode) 解法: class Solution { public:string reorganizeString(string s){string res;//因为1 < s.length < 500 , uint64_t 类型足够uint16_t n s.size();if (n 0) {return res;}unordere…...
IO进程线程复习
IO进程线程复习...
深入理解Linux内核的虚拟地址到物理地址转换机制及缓存优化
在现代计算机系统中,虚拟地址到物理地址的转换是操作系统内存管理的重要组成部分。特别是在基于x86_64架构的Linux系统上,这一转换过程及其相关的缓存机制对系统性能和稳定性至关重要。本文将深入探讨Debian 10上运行Linux 4.19内核时,这些机制的实现细节,特别是页表管理、…...
2025年01月29日Github流行趋势
项目名称:Janus 项目地址url:https://github.com/deepseek-ai/Janus项目语言:Python历史star数:9350今日star数:5969项目维护者:learningpro, hills-code, TheOneTrueGuy, mowentian, soloice项目简介&…...
yolov11、yolov8部署的7种方法(yolov11、yolov8部署rknn的7种方法),一天一种部署方法,7天入门部署
由于涉及量化、部署两个领域,本博文难免有不对之处,欢迎指正。 本博客对 yolov11(yolov8)尝试了7种不同的部署方法,在最基础的模型上一步一步的去掉解码相关的操作(移到后处理种进行)࿰…...
【ArcGIS遇上Python】批量提取多波段影像至单个波段
本案例基于ArcGIS python,将landsat影像的7个波段影像数据,批量提取至单个波段。 相关阅读:【ArcGIS微课1000例】0141:提取多波段影像中的单个波段 文章目录 一、数据准备二、效果比对二、python批处理1. 编写python代码2. 运行代码一、数据准备 实验数据及完整的python位…...
Node.js MySQL:深度解析与最佳实践
Node.js MySQL:深度解析与最佳实践 引言 Node.js作为一种流行的JavaScript运行时环境,以其轻量级、高性能和事件驱动模型受到开发者的青睐。MySQL则是一款功能强大的关系型数据库管理系统,广泛应用于各种规模的应用程序中。本文将深入探讨Node.js与MySQL的集成,分析其优势…...
wordpress外贸独立站常用询盘软件
LiveChat LiveChat是一家提供实时聊天软件的公司,帮助企业通过其平台与客户进行即时通讯,提高客户满意度和忠诚度。他们的产品允许企业在网站、应用程序或电子邮件等多个渠道与客户互动,从而提升客户体验并促进销售增长。 LiveChat的软件特…...
Kotlin 委托详解
Kotlin 委托详解 引言 Kotlin 作为一种现代化的编程语言,在 Android 开发等领域得到了广泛的应用。在 Kotlin 中,委托(Delegation)是一种强大的特性,它可以让我们以更简洁的方式实现代码的复用和扩展。本文将详细解析…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
