Rustのimpl書き方が覚えられないのでまとめてみた
まえがき
Rustの impl
は、traitやジェネリクスを使う場合の書き方が少々覚えにくく感じます。しょっちゅうググって調べ直してしまうので、ひとつの記事にまとめてみました。
impl
宣言パターン
impl
基本形
サンプルコード出典はこちら。
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
ある構造体に対し、それが保有する値を用いたメソッドを定義しています。
今の所ややこしいことはありません。説明なくても読めばなんとなく想像がつく。
ジェネリクスを使用する場合
サンプルコード出典はこちら。
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
fn main() {
let p = Point { x: 5, y: 10 };
println!("p.x = {}", p.x());
}
impl<T> Point<T>
というのがぱっと見で意味がつかめなくて、何度も確認してしまう記法です。
構造体がジェネリクス T
を使用しており、実装するメソッド内でもTを扱う必要がある場合は、 impl <T>
から宣言を始める必要があります。
逆にTを宣言せず、Tが特定の型である場合にだけ使えるメソッドを実装することもできます。
struct Point<T> {
x: T,
y: T,
}
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
トレイトを実装する場合
サンプルコード出典はこちら。
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
トレイトが何であるのかの説明は省略します[1]。
impl A for B
と宣言した時、メソッドを実装しているのはBに対してである、というのが自分が混乱してしまったポイントのように思います。
複合型
サンプルコード出典はこちら。
上記2つのややこしいと感じた記法は、同時に使う事が出来ます。
use std::ops::Deref;
struct DerefExample<T> {
value: T
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
DerefExampleという構造体に対し、Deref traitを実装しています。
DerefExampleはジェネリクスを使って定義されており、実装の中でジェネリクスを使う必要があるため、 imple<T>
と先頭で宣言しています。
まとめ
The Bookを一通り読むと全部書いてある事なのですが、ソースコードを読んでいてふと遭遇した時に上手く理解できない事が多かったので、今回まとめてみました。
-
interfaceのようなもの、と説明されることもありますが個人的には違うと思っています。PHPのtraitは詳しくなくて比較ができません。正直トレイトとは何か、でもう1記事書く気すらしています。そのため今回は省略です。 ↩︎
Discussion