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

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
博客园_首页
WordPress大学
WordPress大学
博客园 - 聂微东
P
Privacy International News Feed
Forbes - Security
Forbes - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Last Week in AI
Last Week in AI
C
CERT Recently Published Vulnerability Notes
月光博客
月光博客
NISL@THU
NISL@THU
美团技术团队
T
Tailwind CSS Blog
Jina AI
Jina AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Apple Machine Learning Research
Apple Machine Learning Research
C
Cisco Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Hacker News
The Hacker News
B
Blog
P
Palo Alto Networks Blog
L
Lohrmann on Cybersecurity
有赞技术团队
有赞技术团队
The Register - Security
The Register - Security
S
Securelist
A
Arctic Wolf
MyScale Blog
MyScale Blog
H
Help Net Security
N
Netflix TechBlog - Medium
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
Threatpost
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Security Latest
Security Latest
T
Tor Project blog
V
Vulnerabilities – Threatpost
V
V2EX
AI
AI
Hugging Face - Blog
Hugging Face - Blog
大猫的无限游戏
大猫的无限游戏
博客园 - Franky
Simon Willison's Weblog
Simon Willison's Weblog
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Troy Hunt's Blog
Schneier on Security
Schneier on Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Heimdal Security Blog
Google Online Security Blog
Google Online Security Blog
Know Your Adversary
Know Your Adversary

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