Files
rust-by-practice/method.html
sunface 987c59ed75 deploy
2025-04-25 12:48:03 +08:00

481 lines
19 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Method &amp; Associated function - Rust By Practice</title>
<!-- Custom HTML head -->
<meta name="description" content="Learn Rust with Example, Exercise and real Practice, written with ❤️ by https://course.rs team">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="theme/style1.css">
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust By Practice</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/sunface/rust-by-practice" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/sunface/rust-by-practice/edit/master/en/src/method.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="associated-functions--methods"><a class="header" href="#associated-functions--methods">Associated functions &amp; Methods</a></h1>
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
<pre><pre class="playground"><code class="language-rust editable edition2021">struct Point {
x: f64,
y: f64,
}
// Implementation block, all `Point` associated functions &amp; methods go in here.
impl Point {
// This is an "associated function" because this function is associated with
// a particular type, that is, Point.
//
// Associated functions don't need to be called with an instance.
// These functions are generally used like constructors.
fn origin() -&gt; Point {
Point { x: 0.0, y: 0.0 }
}
// Another associated function, taking two arguments:
fn new(x: f64, y: f64) -&gt; Point {
Point { x: x, y: y }
}
}
struct Rectangle {
p1: Point,
p2: Point,
}
impl Rectangle {
// This is a method.
// `&amp;self` is sugar for `self: &amp;Self`, where `Self` is the type of the
// caller object. In this case `Self` = `Rectangle`
fn area(&amp;self) -&gt; f64 {
// `self` gives access to the struct fields via the dot operator.
let Point { x: x1, y: y1 } = self.p1;
let Point { x: x2, y: y2 } = self.p2;
// `abs` is a `f64` method that returns the absolute value of the
// caller
((x1 - x2) * (y1 - y2)).abs()
}
fn perimeter(&amp;self) -&gt; f64 {
let Point { x: x1, y: y1 } = self.p1;
let Point { x: x2, y: y2 } = self.p2;
2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
}
// This method requires the caller object to be mutable
// `&amp;mut self` desugars to `self: &amp;mut Self`
fn translate(&amp;mut self, x: f64, y: f64) {
self.p1.x += x;
self.p2.x += x;
self.p1.y += y;
self.p2.y += y;
}
}
// `Pair` owns resources: two heap allocated integers.
struct Pair(Box&lt;i32&gt;, Box&lt;i32&gt;);
impl Pair {
// This method "consumes" the resources of the caller object
// `self` desugars to `self: Self`
fn destroy(self) {
// Destructure `self`
let Pair(first, second) = self;
println!("Destroying Pair({}, {})", first, second);
// `first` and `second` go out of scope and get freed.
}
}
fn main() {
let rectangle = Rectangle {
// Associated functions are called using double colons
p1: Point::origin(),
p2: Point::new(3.0, 4.0),
};
// Methods are called using the dot operator.
// Note that the first argument `&amp;self` is implicitly passed, i.e.
// `rectangle.perimeter()` === `Rectangle::perimeter(&amp;rectangle)`
println!("Rectangle perimeter: {}", rectangle.perimeter());
println!("Rectangle area: {}", rectangle.area());
let mut square = Rectangle {
p1: Point::origin(),
p2: Point::new(1.0, 1.0),
};
// Error! `rectangle` is immutable, but this method requires a mutable
// object.
//rectangle.translate(1.0, 0.0);
// TODO ^ Try uncommenting this line
// Okay! Mutable objects can call mutable methods
square.translate(1.0, 1.0);
let pair = Pair(Box::new(1), Box::new(2));
pair.destroy();
// Error! Previous `destroy` call "consumed" `pair`
//pair.destroy();
// TODO ^ Try uncommenting this line
}</code></pre></pre>
<h2 id="exercises"><a class="header" href="#exercises">Exercises</a></h2>
<h3 id="method"><a class="header" href="#method">Method</a></h3>
<ol>
<li>🌟🌟 Methods are similar to functions: Declare with <code>fn</code>, have parameters and a return value. Unlike functions, methods are defined within the context of a struct (or an enum or a trait object), and their first parameter is always <code>self</code>, which represents the instance of the struct the method is being called on.</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// Complete the area method which return the area of a Rectangle.
fn area
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
assert_eq!(rect1.area(), 1500);
println!("Success!");
}</code></pre></pre>
<ol start="2">
<li>🌟🌟 <code>self</code> will take the ownership of current struct instance, however, <code>&amp;self</code> will only borrow a reference from the instance.</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">// Only fill in the blanks, DON'T remove any line!
#[derive(Debug)]
struct TrafficLight {
color: String,
}
impl TrafficLight {
pub fn show_state(__) {
println!("the current state is {}", __.color);
}
}
fn main() {
let light = TrafficLight{
color: "red".to_owned(),
};
// Don't take the ownership of `light` here.
light.show_state();
// ... Otherwise, there will be an error below
println!("{:?}", light);
}</code></pre></pre>
<ol start="3">
<li>🌟🌟 The <code>&amp;self</code> is actually short for <code>self: &amp;Self</code>. Within an <code>impl</code> block, the type <code>Self</code> is an alias for the type that the <code>impl</code> block is for. Methods must have a parameter named <code>self</code> of type <code>Self</code> for their first parameter, so Rust lets you abbreviate this with only the name <code>self</code> in the first parameter spot.</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">struct TrafficLight {
color: String,
}
impl TrafficLight {
// Using `Self` to fill in the blank.
pub fn show_state(__) {
println!("the current state is {}", self.color);
}
// Fill in the blank, DON'T use any variants of `Self`.
pub fn change_state(__) {
self.color = "green".to_string()
}
}
fn main() {
println!("Success!");
}</code></pre></pre>
<h3 id="associated-functions"><a class="header" href="#associated-functions">Associated functions</a></h3>
<ol start="4">
<li>🌟🌟 All functions defined within an <code>impl</code> block are called associated functions because theyre associated with the type named after the <code>impl</code>. We can define associated functions that dont have <code>self</code> as their first parameter (and thus are not methods) because they dont need an instance of the type to work with.</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">#[derive(Debug)]
struct TrafficLight {
color: String,
}
impl TrafficLight {
// 1. Implement an associated function `new`,
// 2. It will return a TrafficLight contains color "red"
// 3. Must use `Self`, DONT use `TrafficLight` in fn signatures or body
pub fn new()
pub fn get_state(&amp;self) -&gt; &amp;str {
&amp;self.color
}
}
fn main() {
let light = TrafficLight::new();
assert_eq!(light.get_state(), "red");
println!("Success!");
}</code></pre></pre>
<h3 id="multiple-impl-blocks"><a class="header" href="#multiple-impl-blocks">Multiple <code>impl</code> blocks</a></h3>
<ol start="5">
<li>🌟 Each struct is allowed to have multiple impl blocks.</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">
struct Rectangle {
width: u32,
height: u32,
}
// Using multiple `impl` blocks to rewrite the code below.
impl Rectangle {
fn area(&amp;self) -&gt; u32 {
self.width * self.height
}
fn can_hold(&amp;self, other: &amp;Rectangle) -&gt; bool {
self.width &gt; other.width &amp;&amp; self.height &gt; other.height
}
}
fn main() {
println!("Success!");
}</code></pre></pre>
<h3 id="enums"><a class="header" href="#enums">Enums</a></h3>
<ol start="6">
<li>🌟🌟🌟 We can also implement methods for enums.</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">
#[derive(Debug)]
enum TrafficLightColor {
Red,
Yellow,
Green,
}
// Implement TrafficLightColor with a method.
impl TrafficLightColor {
}
fn main() {
let c = TrafficLightColor::Yellow;
assert_eq!(c.color(), "yellow");
println!("{:?}",c);
}</code></pre></pre>
<h2 id="practice"><a class="header" href="#practice">Practice</a></h2>
<p>@todo</p>
<blockquote>
<p>You can find the solutions <a href="https://github.com/sunface/rust-by-practice">here</a>(under the solutions path), but only use it when you need it</p>
</blockquote>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="pattern-match/patterns.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="generics-traits/intro.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="pattern-match/patterns.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="generics-traits/intro.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="ace.js"></script>
<script src="editor.js"></script>
<script src="mode-rust.js"></script>
<script src="theme-dawn.js"></script>
<script src="theme-tomorrow_night.js"></script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
<script src="assets/custom3.js"></script>
<script src="assets/lang1.js"></script>
</div>
</body>
</html>