SudachiPyのoutパラメーター

## はじめに
SudachiPyのいくつかのメソッドに`out`パラメーターが存在します。その引数として`MorphemeList`を渡すと、新しい`MorphemeList`を返す代わりに、渡された`MorphemeList`の中身が上書きされます。この挙動は[NumPy](https://numpy.org/doc/stable/reference/generated/numpy.matmul.html)によく似ています。

## 対応API

* [`Tokenizer.tokenize()`](https://worksapplications.github.io/sudachi.rs/python/api/sudachipy.html#sudachipy.Tokenizer.tokenize)
* [`Morpheme.split()`](https://worksapplications.github.io/sudachi.rs/python/api/sudachipy.html#sudachipy.Morpheme.split)
* [`Dictionary.lookup()`](https://worksapplications.github.io/sudachi.rs/python/api/sudachipy.html#sudachipy.Dictionary.lookup) (次のバージョン以降のAPI）

## 使い方

`out`パラメーターとしてMorphemeListを渡すと、返り値は同じインスタンスになります。
```python
from sudachipy import Dictionary, SplitMode
tokenizer = Dictionary().create(SplitMode.C)
a_morphemes = tokenizer.tokenize('関西国際空港に行く')
b_morphemes = tokenizer.tokenize('東京に行く', out=a_morphemes)
print(a_morphemes)
print(a_morphemes is b_morphemes)
```
```
東京 に 行く
True
```

### `Morpheme`は`MorphemeList`の中身を参照している

注意しなければいけないのは、`Morpheme`は独立のオブジェクトではなく、あくまで`MorphemeList`の中を参照しているにすぎません。`MorphemeList`を再利用する場合は、`Morpheme`の中身も自動的に変わります。

```python
from sudachipy import Dictionary, SplitMode
tokenizer = Dictionary().create(SplitMode.C)
a_morphemes = tokenizer.tokenize('関西国際空港に行く')
m = a_morphemes[0]
print(m)
tokenizer.tokenize('東京に行く', out=a_morphemes)
print(m)
```
```
関西国際空港
東京
```

もし正しくない`Morpheme`を参照している場合はエラーになります。
```python
from sudachipy import Dictionary, SplitMode
tokenizer = Dictionary().create(SplitMode.C)
a_morphemes = tokenizer.tokenize('関西国際空港にいった')
m = a_morphemes[-1]
print(m)
b_morphemes = tokenizer.tokenize('東京に行く', out=a_morphemes)
print(m)
```
```
た
thread '<unnamed>' panicked at 'index out of bounds: the len is 3 but the index is 3', sudachi.rs\sudachi\src\analysis\mlist.rs:171:25
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "scratch_1.py", line 7, in <module>
    print(m)
pyo3_runtime.PanicException: index out of bounds: the len is 3 but the index is 3
```

`Morpheme`を不用意に長期間保持しないことをお勧めします。

## 応用例

### すべての分割モードの形態素を羅列する

この機能の応用例として、すべての分割モードで入力を解析する方法を示します。

```python
from sudachipy import Dictionary, SplitMode
tokenizer = Dictionary().create(SplitMode.C)

# MorphemeListの初期化
a_morphemes = tokenizer.tokenize('')
b_morphemes = tokenizer.tokenize('')

text = '美術館と国会議事堂前に行く'
c_morphemes = tokenizer.tokenize(text)
for c_morph in c_morphemes:
    print(f'{c_morph=}')
    if c_morph.split(SplitMode.B, out=b_morphemes, add_single=False):
        for b_morph in b_morphemes:
            print(f'\t{b_morph=}')
            if b_morph.split(SplitMode.A, out=a_morphemes, add_single=False):
                for a_morph in a_morphemes:
                    print(f'\t\t{a_morph=}')
    elif c_morph.split(SplitMode.A, out=a_morphemes, add_single=False):
        for a_morph in a_morphemes:
            print(f'\t\t{a_morph=}')
```
```
c_morph=<Morpheme(美術館, 0:3, (0, 1472589))>
        a_morph=<Morpheme(美術, 0:2, (0, 631220))>
        a_morph=<Morpheme(館, 2:3, (0, 753593))>
c_morph=<Morpheme(と, 3:4, (0, 102127))>
c_morph=<Morpheme(国会議事堂前, 4:10, (0, 1041988))>
    b_morph=<Morpheme(国会, 4:6, (0, 364213))>
    b_morph=<Morpheme(議事堂, 6:9, (0, 1523020))>
        a_morph=<Morpheme(議事, 6:8, (0, 686995))>
        a_morph=<Morpheme(堂, 8:9, (0, 368467))>
    b_morph=<Morpheme(前, 9:10, (0, 318429))>
c_morph=<Morpheme(に, 10:11, (0, 113651))>
c_morph=<Morpheme(行く, 11:13, (0, 660689))>
```

## 終わりに

この機能は主にユーザの利便性のために開発されました。メモリーの再利用で少しの高速化（数パーセント程度）はできますが、まだ改善の余地があります。

ではよい Sudachi life を。