RUST 每日一省:全局变量

2023-09-14 15:10:14

Rust中允许存在全局变量。它们一般有两种:常数和静态值。

常量

        我们使用关键字 const 来创建常量。由于常量未使用关键字 let 声明,因此在创建它们时必须指定类型。常量只能进行简单赋值,并且没有固定的内存地址,无论它们在何处使用都会被内联。

        常量不能遮蔽,不能重复定义。也就是说,不存在内层或后面作用域定义的常量去遮蔽外层或前面定义的同名常量的情况。常量一旦定义后就永远不可变更和重新赋值。

const HEADER: u64 = 32;
fn main() {
    println!("{:?}", HEADER);
}

静态

        静态变量使用 static 关键字定义, 跟常量一样需要显式指明类型,静态变量的生命周期也是全局的,因为它具有固定的内存位置,并且在整个程序中作为单个(唯一)实例存在。

        静态变量并非被分配到栈中, 也不是在堆中, 而是和程序代码一起被存储于静态存储区中。 静态存储区是伴随着程序的二进制文件的生成(编译时) 被分配的, 并且在程序的整个运行期都会存在。

        静态变量默认同样不可修改,因此无法取得某个值的mut 引用。static 可以声明为 mut,但再访问它就是不安全的,需要使用unsafe。

static mut APPLE: u32 = 4;
static BANANA: u8 = 9;

fn main() {
    unsafe {
        println!("APPLEis {}", APPLE);
        APPLE= 42;
        println!("APPLE is now {}", APPLE);
        println!("BANANAis {}", BANANA);
    }
}

对比

常量和静态变量非常相似,但它们之间存在一些微妙的区别:

        静态变量的值在内存中拥有固定的地址,使用它的值总是会访问到同样的数据。与之相反的是,常量则允许在任何被使用到的时候复制其数据。另外一个区别在于静态变量是可变的。需要注意的是,访问和修改可变的静态变量是不安全的 。

        如果你不需要依赖静态的单例属性及其预定义的内存位置,而只需要其具体值,那么应该更倾向于使用常量。它们允许编译器进行更好的优化,并且更易于使用。

lazy_static

        全局值只能在初始化时声明非动态的类型,并且在编译期,它在堆栈上的大小是已知的。例如,你不能将 HashMap 创建为静态值,因为它涉及堆分配。幸运的是,我们可以使用 HashMap 和其他动态集合类型(如 Vec)构造全局静态值,这是通过被称为lazy_static 的第三方软件包实现的。它暴露了 lazy_static!宏,可用于初始化任何能够从程序中的任何位置全局访问的动态类型。

use std::sync::Mutex;
lazy_static! {
    static ref ITEMS: Mutex<Vec<u64>> = {
        let mut v = vec![];
        v.push(9);
        v.push(2);
        v.push(1);
        Mutex::new(v)
    }
}

        使用 lazy_static!宏声明的元素需要实现 Sync 特征。这意味着如果某个静态值可变,那么必须使用诸如 Mutex 或 RwLock 这样的多线程类型。

        使用 lazy_static! 会在每次访问静态数据时造成微小的性能损失,因为其实现使用了为一次性初始化而设计的一个低级同步原语 std::sync::Once。在后台,每次访问懒静态数据,程序都要执行一次原子加载指令以检查初始化是否完成。

更多推荐

构建无限画布,协作数字绘图 | 开源日报 0915

tldraw/tldrawStars:16.4kLicense:Apache-2.0tldraw是一个协作数字白板项目,可在tldraw.com上使用。它的编辑器、用户界面和其他底层库都是开源的,并且可以通过npm进行分发。您可以使用tldraw为产品创建一个即插即用的白板,或者将其作为构建自己无限画布应用程序的基础。

小程序开发一个多少钱啊

在今天的数字化时代,小程序已经成为一种非常流行的应用程序形式。由于它们的便捷性、易用性和多功能性,小程序吸引了越来越多的用户和企业。但是,很多人在考虑开发一个小程序时,都会遇到同一个问题:开发一个小程序需要多少钱?小程序的开发费用因人而异,取决于多种因素。下面,我们将为您详细列出影响小程序开发费用的主要因素。1、功能需

Bean的生命周期

SpringBean的生命周期是从Bean实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为SpringBean的生命周期。小枫叶一,实例化1.1Bean工厂后处理器–BeanFactoryPostProcessorBeanFactoryPostProcessor是一个

怎样判断一个数是否为偶数

要求代码行数尽可能少;packagemainimport("fmt""strconv")funcmain(){fmt.Printf("传入的值是否为奇数:%t\n",Judge_is_even(7))}funcJudge_is_even(numint)bool{//fmt.Println(num%2)rs,_:=str

modbus的协议

在介绍Modbus协议之前,我们要先了解下RS485协议,因为Modbus协议是在RS485这个硬件层协议上搭建的软件层协议。RS485特性半双工。用缆线两端的电压差值来表示传递信号。RS485的特点包括1.S485的电气特性:逻辑“1”以两线间的电压差为+(2~6)V表示;逻辑“0”以两线间的电压差为-(2~6)V表

ChatGPT Prompting开发实战(八)

一.什么是归纳总结式的prompt开发有时候需要对一段文本进行归纳总结,那么可以采取以下的方案:-按照给定单词、句子或者字符的数量限制来让模型裁剪文本,使内容更精炼-基于聚焦的主题进行总结-只根据需求抽取相关的文本信息,不需要整段文本内容除了上面列出的几种方式之外,还可能有额外的一些需求,譬如给出多段文本,要求模型同时

JUnit测试进阶(Private测试)

Private测试前言一、间接调用二、Java反射机制调用前言在单元测试中,由于私有方法(PrivateMethod)无法直接被调用,因此对私有方法进行测试成为一项难题。一个可行的方法是:在测试时将私有方法改变为公有方法(PublicMethod),在测试完成后再将其修改为私有方法。然而,该方法操作过程比较复杂,不利于

Redis面试题(五)

文章目录前言一、使用过Redis做异步队列么,你是怎么用的?有什么缺点?二、什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?总结前言使用过Redis做异步队列么,你是怎么用的?有什么缺点?什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?`一、使用过Redis做异步队列么,你是怎么用的?有什么缺点?一般使用lis

Windows开机密码破解

目前可行的方法(目前只能通过进PE的方式进行密码的修改)通过本文最后“本文参考网页”下载Rufus写盘工具和Hiren’sBootCDPE镜像启动写盘工具,选择U盘和镜像U盘插入电脑时确保电脑为关机状态启动电脑,快速敲击Delete键,进入Bios界面(不同的电脑是通过不同的按键进入BIOS,可以利用搜索引擎查看你的电

腾讯会议核心存储治理:Redis分库和异地多活

👉导读会控为整个会议最为核心的业务,由于海量请求的高性能要求,后台存储全部为Redis。在业务飞速发展期,各模块边界不够清晰,大家对存储的使用处于失控状态,随着PCU的不断上涨,逐步暴露出存储和架构的诸多问题,同时也对系统容灾能力有了更高的要求。会控业务历史包袱重,存储改造伤筋动骨,要做到平滑迁移需要考虑的细节较多。

常用注解梳理

@RestController注解:将一个类标识为一个RESTful风格的控制器,用于处理HTTP请求和响应。@RequestMapping注解:用于将一个HTTP请求映射到控制器的处理方法上,可以用于类级别和方法级别。@PostMapping注解:用于将HTTPPOST请求映射到控制器的处理方法上。@GetMappi

热文推荐