Help us understand the problem. What is going on with this article?

RustでCall Operator Overloadしようとして躓いた。

More than 1 year has passed since last update.

背景

プログラミングする際にCall OperatorをしょっちゅうOverloadして使うんですがC++とかPythonと違ってOverloadの仕方がちょっと特殊?な上に全然関連ドキュメントが出てこないので備忘録がてらにメモしておきます。

C++/PythonでのOperator Overload

自分がある程度書いていてOperator Overloadができる言語がC++/Pythonあたりしかなかったのでその2言語での例になりますがやり方はいずれも以下の通りです。

C++

#include <iostream>
#include <string>

class Foo {
public:
  void operator()(std::string arg) {std::cout << "Hello, " << arg << "!" << std::endl;}
};

Python

class Foo:
  def __init__(self):
    pass

  def __call__(self, arg):
    print "Hello {}!".format(arg)

いずれもクラス定義の中で関連する関数をOverloadすればおしまいですね。

RustでのOperator Overload

普通の演算子のOverloadでさえちょっと面倒なのにCall Operatorでは更に一手間必要です。というのもRustにはオブジェクトという概念が存在しないのでCall OperatorをもったTraitを実装してやることでOperator Overloadを実現するんですがそのためのTraitが三種類 (FnOnce, FnMut, Fn) 存在します。そしてFnMutの実装にはFnOnceの実装が必要で、Fnの実装にはFnMutの実装が必要というなんとも面倒な仕様になっています。

use std::ops::{FnOnce, FnMut, Fn};

struct Foo {}

impl FnOnce for Foo {
  type Output = (); // 返り値は無し
  extern "rust-call" fn call_once(self, (arg,): (String,)) -> Self::Output {
    println!("Hello {}!", arg);
  }
}

impl FnMut for Foo {
  extern "rust-call" fn call_mut(&mut self, (arg,): (String,)) -> Self::Output {
    println!("Hello {}!", arg);
  }
}

impl Fn for Foo {
  extern "rust-call" fn call(&self, (arg,): (String,)) -> Self::Output {
    println!("Hello {}!", arg);
  }
}

selfが呼び出し時にconsumeされてもいいのであればFnOnceだけ実装してあげればいいんですがそうでなく単純にImmutableなReferenceを貸したいだけの時はFnMutFnを実装してやる必要があります。なんでこうなったのかはわかりませんがそういうものみたいです。めんどくさい。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away