改进rust代码的35种具体方法-类型(二十二)-最小化可见度

本文主要是介绍改进rust代码的35种具体方法-类型(二十二)-最小化可见度,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇文章 改进rust代码的35种具体方法-类型(二十一)-熟悉Cargo.toml版本使用


Rust允许将代码元素隐藏或暴露给代码库的其他部分。本项目探讨了为此提供的机制,并就应在何时何地使用它们提出建议。

可见性语法

Rust的基本可见性单位是模块。默认情况下,模块的项目(类型、方法、常量)是私有的,只能访问同一模块及其子模块中的代码。

需要更广泛可用的代码用pub关键字标记,使其向其他范围公开。对于大多数Rust语法功能,使功能pub不会自动公开内容——pub mod中的类型和功能不是公开的,也不是pub struct中的字段。然而,有几个例外情况是,将可见性应用于内容是有意义的:

  • 公开枚举会自动使类型的变体也公开(以及这些变体中可能存在的任何字段)。
  • 公开trait会自动公开该特征的方法。

因此,模块中的类型集合:

pub mod somemodule {// Making a `struct` public does not make its fields public.#[derive(Debug, Default)]pub struct AStruct {// By default fields are inaccessible.count: i32,// Fields have to be explicitly marked `pub` to be visible.pub name: String,}// Likewise, methods on the struct need individual `pub` markers.impl AStruct {// By default methods are inaccessible.fn canonical_name(&self) -> String {self.name.to_lowercase()}// Methods have to be explicitly marked `pub` to be visible.pub fn id(&self) -> String {format!("{}-{}", self.canonical_name(), self.count)}}// Making an `enum` public also makes all of its variants public.#[derive(Debug)]pub enum AnEnum {VariantOne,// Fields in variants are also made public.VariantTwo(u32),VariantThree { name: String, value: String },}// Making a `trait` public also makes all of its methods public.pub trait DoSomething {fn do_something(&self, arg: i32);}
}

允许访问pub的东西和前面提到的例外情况:

use somemodule::*;let mut s = AStruct::default();
s.name = "Miles".to_string();
println!("s = {:?}, name='{}', id={}", s, s.name, s.id());let e = AnEnum::VariantTwo(42);
println!("e = {e:?}");#[derive(Default)]
pub struct DoesSomething;
impl DoSomething for DoesSomething {fn do_something(&self, _arg: i32) {}
}let d = DoesSomething::default();
d.do_something(42);

但非pub的东西通常无法进入:

let mut s = AStruct::default();
s.name = "Miles".to_string();
println!("(inaccessible) s.count={}", s.count);
println!("(inaccessible) s.canonical_name()={}", s.canonical_name());
error[E0616]: field `count` of struct `somemodule::AStruct` is private--> src/main.rs:230:45|
230 |     println!("(inaccessible) s.count={}", s.count);|                                             ^^^^^ private field
error[E0624]: method `canonical_name` is private--> src/main.rs:231:56|
86  |         fn canonical_name(&self) -> String {|         ---------------------------------- private method defined here
...
231 |     println!("(inaccessible) s.canonical_name()={}", s.canonical_name());|                                         private method ^^^^^^^^^^^^^^
Some errors have detailed explanations: E0616, E0624.
For more information about an error, try `rustc --explain E0616`.

最常见的可见性标记是裸露的pub关键字,它使该项目对任何能够看到它所在的模块的东西可见。最后一个细节很重要:如果asomecratesomecrate::somemodule模块首先对其他代码不可见,那么它里面的任何pub仍然不可见。

然而,pub也有一些更具体的变体,允许限制可见性的范围。按有用性降序排列,如下所示:

如果您有一个对模块私有但未在该模块(及其子模块)中使用的代码项,Rust编译器将警告您:

pub mod anothermodule {// Private function that is not used within its module.fn inaccessible_fn(x: i32) -> i32 {x + 3}
}

虽然警告表示代码在其拥有的模块中“从未使用过”,但在实践中,此警告通常表明代码不能从模块外部使用,因为可见性限制不允许:

warning: function `inaccessible_fn` is never used--> src/main.rs:56:8|
56 |     fn inaccessible_fn(x: i32) -> i32 {|        ^^^^^^^^^^^^^^^|= note: `#[warn(dead_code)]` on by default

可见性语义

与如何提高知名度的问题不同,是何时这样做的问题。对此普遍接受的答案尽可能少,至少对于任何将来可能被使用和重复使用的代码。

提出这个建议的第一个原因是,可见性的变更很难撤销。一旦一个 crate 项是公共的,就不能再将其设置为私有,否则会破坏使用 crate 的任何代码,从而需要进行主要版本的升级。相反,事实并非如此:将私人项目移动为公共项目通常只需要一个次要版本颠簸,并且不会让板条箱用户不受影响——阅读Rust的API兼容性指南,并注意只有当有pub项目在起作用时,才会注意到有多少是相关的。

一个更重要但更微妙的偏爱隐私的理由是,它让你的选择保持开放。暴露的东西越多,未来需要固定的东西就越多(没有不兼容的变化)。如果您公开数据结构的内部实现细节,那么未来使用更高效算法的假定更改将成为突破性更改。如果您公开内部助手函数,一些外部代码将不可避免地取决于这些函数的确切细节。

当然,这只适用于可能具有多个用户且寿命较长的库代码。但没有什么比临时解决方案更永久的了,所以这是一个好习惯。

同样值得注意的是,这种限制可见性的建议绝不是这个项目或Rust所独有的:

这篇关于改进rust代码的35种具体方法-类型(二十二)-最小化可见度的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1064071

相关文章

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

nginx-rtmp-module模块实现视频点播的示例代码

《nginx-rtmp-module模块实现视频点播的示例代码》本文主要介绍了nginx-rtmp-module模块实现视频点播,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录预置条件Nginx点播基本配置点播远程文件指定多个播放位置参考预置条件配置点播服务器 192.