惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
M
MIT News - Artificial intelligence
T
Tailwind CSS Blog
Webroot Blog
Webroot Blog
S
Secure Thoughts
N
News and Events Feed by Topic
月光博客
月光博客
TaoSecurity Blog
TaoSecurity Blog
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
N
News | PayPal Newsroom
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
小众软件
小众软件
Recent Commits to openclaw:main
Recent Commits to openclaw:main
P
Privacy & Cybersecurity Law Blog
GbyAI
GbyAI
K
Kaspersky official blog
WordPress大学
WordPress大学
P
Proofpoint News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 叶小钗
W
WeLiveSecurity
Jina AI
Jina AI
The Cloudflare Blog
Project Zero
Project Zero
Simon Willison's Weblog
Simon Willison's Weblog
V
Vulnerabilities – Threatpost
L
LangChain Blog
Forbes - Security
Forbes - Security
PCI Perspectives
PCI Perspectives
Engineering at Meta
Engineering at Meta
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
博客园 - 【当耐特】
H
Heimdal Security Blog
A
About on SuperTechFans
Cisco Talos Blog
Cisco Talos Blog
T
Threat Research - Cisco Blogs
云风的 BLOG
云风的 BLOG
Spread Privacy
Spread Privacy
L
LINUX DO - 最新话题
L
Lohrmann on Cybersecurity
Last Week in AI
Last Week in AI
Google DeepMind News
Google DeepMind News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
I
Intezer
Martin Fowler
Martin Fowler
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint

Whexy Blog

We lost the AIxCC. So, what now? Arm VMM with Apple's Hypervisor Framework Driving WaveShare E‐Paper Display with a Raspberry Pi Pico in MicroPython Use cgroup v2 inside docker containers Annual Hit Piece: Fuzzing Top Conference Paper Debunking Report Solving SSH Key Login Issues on Synology NAS Can SSD Cache Improve Synology NAS Write Speeds? Virtualization is all you need Running Windows Games on Mac Without Virtual Machines Tears of the Kingdom: End of an Era Anonymous CDN Traffic Relay Self-host Relay Service with CDN Home Networking Solution Building Your Own Blog System Connecting Smart Devices to SUSTech Campus Network Function Color Theory Stop Forkin' Around: Faster Creating of Large Processes on Linux PMU Interrupts: How to handle them Asynchronous Mutex Using QEMU to run Linux images on M1 Macbook Alligator In Vest - My first research work Experience Using Several Plugins in Complex LaTeX Projects Understanding Rust Generic Traits SUSTeam: Ultimate Gaming Platform Inline Assembly Language in C React Learning Notes Building a School Bus Schedule App for Apple Watch 12307 Train Ticket Purchase Platform Sakai and Local Folder Synchronization Building a Super Simple OpenJudge in Two Nights Setting Up Remote Backup for macOS Shell Script for Automatically Logging into SUSTech Campus Network Building a Movie Streaming System in the Dorm
Variance in Rust
Whexy · 2021-02-21 · via Whexy Blog

Whexy /

February 21, 2021

I’m watching Jon Gjengset’s live coding stream. And the topic is “Subtyping and Variance”. This is my note.

Jon Gjengset’s live coding stream

The Rust compiler will automatically shrink the lifetime of the parameter to the shortest one. For example,

fn main() {
	let s = String::new();
	let x = "static str"; // `x` is `&'static str`
	let mut y = &*s; // `y` is `&'s str`
	y = x;
	// Still compilable!
  // Rust automatically shrink the lifetime static to s.
}

That makes sense, because you can always trust a value from who lives longer, without concerning about the value somehow goes invalid. What’s behind the scene is that Rust have a system of subtyping and variance.

Just think of an example in Java, class Cat is a subtype of the class Animal. In brief, we say T is a subtype of U (notation T <: U) when T is at least as useful as U. T can do anything that U can do, but T may have the ability of other things. In Rust, the lifetime ’static is a subtype of every lifetime. Rust compiler then uses different variance rules to check whether the program should be compiled or not.

You may understand variance in many other programming languages. And there are three types of variance in programming, called covariance, contra-variance, and invariance.

Covariance

Covariance is the most common case. Most things in Rust is covariance. For example,

/// define a function which takes an lifetime sticker `a`
fn foo(_: &'a str) {}

// and you can call the function with
foo(&'a str);
// or
foo(&'static str);

In the example, we can give the function with parameter whose lifetime is no matter a or static. That is because static is a subtype of a. The static str lives longer than the required ’a, so there should be no concern that the borrowed variable would be unexpectedly dropped.

Contra-variance

Let’s consider the high-rank function example below.

/// define a function which takes a function,
/// which takes a lifetime sticker `a`.
fn foo(bar: Fn(&'a str) -> ()) {
	bar(str);
}

let x : Fn(&'a str) -> ();
foo(x); // that makes sense.

let y : Fn(&'static str) -> ();
foo(y); // should that make sense ???

Should foo(y) be compilable? Definitely not! Let’s say if foo(y) compiles, then we are actually doing things in the high-rank function like:

let baz = &*String::new();
// lifetime of baz is shorter than 'static
fn y(_: &'static str) {}
// an function that needs a static borrowing
y(baz);
// [!!] Should not compile
// because a static lifetime is required.

The caller gives a parameter with limited lifetime. But the function we get requires a static lifetime parameter. That cannot be allowed. However, let’s consider another example:

/// define a function which takes a function,
/// which takes a parameter with static lifetime.
fn foo(bar: Fn(&'static str) -> ()) {
	bar("Hello Whexy~");
}

let x : Fn(&'static str) -> ();
foo(x); // that makes sense.

let y : Fn(&'a str) -> ();
foo(y); // that makes sense too.

This example is perfect compiled. Because the function y requires a parameter with limited lifetime. The caller gives it a static parameter which lives longer. Again, there should be no concern that the borrowed variable would be unexpectedly dropped. So the contra-variance is a specific rule. T <: U ==> Fn(U) <: Fn(T)

Invariance

Invariance means “no variance”. In a short word, “just pass me exact the thing I require, no tricks.” Let’s see this example:

fn foo(s: &mut &'a str, x: &'a str) {
	*s = x;
}
let mut x = "Hello"; // x : &'static str
let z = String::new();
foo(x, &z); // foo(&'static str, &'z str)
drop(z);
println!("{}", x); // OOPS!

The code cannot compile, because we are going to access x, which points to a dropped memory area. In fact, in &'a mut T, T is invariance. However, the 'a is covariance. It’s not hard to figure out, so I’m left this to you as an exercise.

Variance of types are listed in “The Rustonomicon”

© LICENSED UNDER CC BY-NC-SA 4.0