Skip to content

Instantly share code, notes, and snippets.

@danielhenrymantilla
Created July 7, 2018 13:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielhenrymantilla/95189c68e15f1f2b252a71dce132d2b2 to your computer and use it in GitHub Desktop.
Save danielhenrymantilla/95189c68e15f1f2b252a71dce132d2b2 to your computer and use it in GitHub Desktop.
Rust: &self sugar vs other &identifier bindings
/* The following lib tests illustrate a lack of consistency in rust:
* the &identifier binding leads to 2 different behaviors based on whether
* - the identifier is the special 'self' first argument of a method,
* - or a simple variable / argument (called slf in the following tests)
*/
#![allow(dead_code, unused_variables, unused_parens)]
/* compiler ensures that check_ref::<T>(x) can only be called iff x: &T */
fn check_ref<T> (_: &T) {}
#[derive(PartialEq)]
struct Slf;
#[derive(Clone, Copy, PartialEq)]
struct SlfCpy;
#[cfg(test)]
mod inline_tests {
use {check_ref, Slf, SlfCpy};
#[test]
fn amptype_notation () // slf: &Slf
{
let slf: &Slf = &Slf; // <-- self: &Self logic here
check_ref::<Slf>(slf);
assert!(slf == &Slf);
/* => slf is a ref */
}
#[test]
fn refself_notation () // ref slf = Slf
{
let ref slf = Slf;
check_ref::<Slf>(slf);
assert!(slf == &Slf);
/* => slf is a ref */
}
#[test]
fn ampself_notation () // &slf
{
let &slf = &SlfCpy; // <-- &self logic here */
// check_ref::<SlfCpy>(slf); // does not compile!
check_ref::<SlfCpy>(&slf); // this does
assert!(&slf == &SlfCpy);
assert!(slf == SlfCpy);
/* => slf is NOT a ref /!\ */
}
#[test]
fn ampself_notation_equivalent () // Explanation:
{
// let &slf = (&SlfCpy); // does a pattern-match equivalent to:
let slf = *(&SlfCpy); // move borrowed value => requires Copy
// check_ref::<SlfCpy>(slf); // Can't compile => slf isn't a ref
check_ref::<SlfCpy>(&slf); // &slf is.
assert!(slf == SlfCpy);
}
/* ===== (&slf) vs (slf: &Slf) -> NOT THE SAME TYPE ===== */
}
#[cfg(test)]
mod function_tests {
use {check_ref, Slf, SlfCpy};
#[test]
fn classic_case ()
{
/* slf functions */
let amptype_notation = |slf: &Slf| {
check_ref::<Slf>(slf);
assert!(slf == &Slf);
/* => slf is a ref */
};
// let ampself_notation_wrong = |&slf| {
// check_ref::<Slf>(slf); // Can't compile => slf isn't a ref
// }
let ampself_notation_right = |&slf| {
check_ref::<SlfCpy>(&slf);
assert!(slf == SlfCpy);
/* => slf is NOT a ref /!\ */
};
let refself_notation = |ref slf| {
check_ref::<Slf>(slf);
assert!(slf == &Slf);
/* => slf is a ref */
};
/* inputs taken */
amptype_notation(&Slf); // a ref
ampself_notation_right(&SlfCpy); // a ref
refself_notation(Slf); // owned value
/* ===== (&slf) vs (slf: &Slf) -> NOT THE SAME TYPE ===== */
}
/* self functions / (static) methods */
impl Slf {
fn amptype_notation (self: &Self) {
check_ref::<Self>(self);
assert!(self == &Slf);
/* => self is a ref */
}
fn ampself_notation_wrong (&self) {
check_ref::<Slf>(self);
assert!(self == &Slf);
/* => self is a ref */
}
// fn ampself_notation_right (&self) {
// check_ref::<Slf>(&self);
// /* => self is indeed a ref */
// }
fn refself_notation (ref slf: Self) {
check_ref::<Self>(slf);
assert!(slf == &Slf);
/* => self is a ref */
}
}
#[test]
fn self_case ()
{
/* inputs taken */
Slf::amptype_notation(&Slf); // a ref
Slf::ampself_notation_wrong(&Slf); // a ref
Slf::refself_notation(Slf); // owned value
/* ===== (&self) vs (self: &Self) -> THE SAME TYPE !?? ===== */
}
#[test]
fn bonus_refself_move_semantics ()
{
let slf = Slf;
Slf::refself_notation(slf); /* slf moved here */
// Slf::refself_notation(slf); /* value cannot be used after move */
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment