Rust part33 (229レス)
上下前次1-新
31: 08/23(土)22:15 ID:vghJtGax(1) AAS
多値の取り扱いの仕方の一つがタプル
そしてRust公式にも Functions can use tuples to return multiple values. と明記されている
>>28の引用文についてRustは関数で多値を返すことができる言語の一つ
32: 08/23(土)22:45 ID:b43T5BM2(1) AAS
Rustのタプルは多値で合っているが、言語によってはタプルというオブジェクト[のポインタ]を1つ返す場合もある。
そのような言語ではタプル≠多値で、Rustではタプル=多値。
Rustで関数がタプルを返す時に、各環境で可能なら複数のレジスタを使って返し、レジスタ返しの数を超えていれば、例えば呼び出し元スタックフレームの指定領域に直接書き込んで返す。
したがってRustは多値返しをサポートする言語。
33: 08/24(日)06:23 ID:yIg8YRK3(1/4) AAS
分野によって用語の意味にブレがあるからそういうのを厳密に考えてもあんまり意味ない。
狭義の多値は継続 (continuation) に複数の値が渡ることをいうのでたぶん >>28 はその意味で言ってて、その意味ではタプルは多値ではない。
単なる言語ユーザの目線ではタプルにまとめて受け渡すことと複数の値を受け渡すことには何も違いはないから同一視しても何も困らないよ。
形式論理とかの世界の話。
34: 08/24(日)06:51 ID:Q1fxgDlW(1) AAS
重要なことはオーバーヘッドの有無
タプルをオブジェクトの一種として扱う言語はオブジェクトを用意してそのアドレス単値のみを渡すため間接アクセスのオーバーヘッドが生じる
タプルを多値として扱うRustは多値として渡せるためオーバーヘッドが生じない
もちろんRustではタプルをBoxに入れることでアドレス単値のみ返すことも可能でオブジェクト方式の言語は常にそれをしていることになる
35(1): 08/24(日)07:38 ID:yIg8YRK3(2/4) AAS
アーキテクチャによって ABI は違うかもしれないけど一般的な実装としては
関数の返却値が大きい時は呼出し側でメモリを確保してそれを隠れた引数として渡すようなメカニズムになってる。
返却値はスタックを介さない。
これは C++ でも同じ。
36: 08/24(日)07:52 ID:lHuVCVKu(1/3) AAS
>>35
ほぼ合っているが一部だけ違う
間違ってる部分は「スタックを介さない」
正解は「スタックを介す」ことで高速に引き渡す
サイズの大きな値を返す場合
具体的には呼び出し元でスタックポインタを増減することでスタックフレームを拡大してその確保領域のアドレスを隠れた引数としてレジスタ渡しする
呼び出された関数側ではその確保領域に直接書き込んで値を返す
ヒープ領域を確保して受け渡す方式と比べるとメモリ領域確保のコストがない点とスタック上でそのままメモリキャッシュに乗る点で有利
37: 08/24(日)07:56 ID:lHuVCVKu(2/3) AAS
ちなみにRustでx64アーキテクチャの時
16バイトまでならレジスタ渡しになり上記スタック領域は使われないため更に速い
38: 08/24(日)08:16 ID:lHuVCVKu(3/3) AAS
ごめん、肝心なところ書き間違えてる
✕ 16バイトまでならレジスタ渡し
○ 16バイトまでならレジスタ返し
39: 08/24(日)10:58 ID:lOj53x5G(1) AAS
言語が多値返却をサポートしてるかどうかというのは文法としてサポートしてるかどうかという意味
文法的にはサポートしてないけど「〇〇使えば多値返却できる」のは当たり前
一般的なプログラミング言語で「Functions can use 〇〇 to return multiple values」の〇〇に当てはまるものがない言語は無いので意味がない
文法的にサポートしているかどうかと内部実装がどの程度最適化されるのかはまた別の話
40(1): 08/24(日)11:01 ID:o5OQy7cK(1/2) AAS
多値が返せるか?の意味なんて、ユーザ的には戻り値の分割代入ができるか?ってだけだし
ダラダラ言わずに返せますで終わりでよくね
41: 08/24(日)11:17 ID:DLpoJrbF(1) AAS
Rustは多値を返す機能があるだけでなく
その実装も本当に多値を返すため効率よく実行も速いことが特徴
42(1): 08/24(日)11:34 ID:yIg8YRK3(3/4) AAS
>>40
仕様を読むときは言語の理屈や用語をわかってないとちゃんと読めない。
複数の要素をひとつにまとめたもの (タプルや構造体) をひとつ返すというのと複数の値を返せるというのは違うことなんだが、
Rust では同一視することにしたというならそれはそれで同一視しているという理屈をわかってないといけない。
43(1): 08/24(日)11:46 ID:s620v8qa(1) AAS
>>42
それは屁理屈
プログラマとしては多値を返せる機能があればよいわけで、
それがタプルという形で実現されていようが困ることは何一つない
逆に、タプルをサポートしていればそれだけで十分であり、
タプルでない多値をサポートするメリットが何もない
44: 08/24(日)11:50 ID:yIg8YRK3(4/4) AAS
>>43
実際に (複数の要素をタプルなどにまとめるのではなく) 多値をサポートしてる言語はあるわけだが、ディスってんの?
言語の理屈の構成の仕方の話であって言語としてのメリットの話なんかしてない。
45: 08/24(日)11:58 ID:sGVh/967(1) AAS
多値をサポートしてる言語の例としてGoが上で挙げられているけどさ
Goはタプルがなくてみんな困っている
タプルがある言語では多値がなくて困った話は聞かれない
機能として『タプル ⊃ 多値』 だからだよ
46: 08/24(日)12:05 ID:DXAve6fe(1) AAS
Goでタプルがなくて辛いという話は聞いたことがないな
最適化の観点抜きで機能的に他でカバーできるから不要と言ってしまうと、
例えばオブジェクトは全部ヒープに置いてスマポの所有権移動だけにしてしまえば複雑なムーブは不要となり遥かにシンプルになる
それはそれで一つの考え方だが、Rustはそういう言語ではないと思っているのだろう?
47: 08/24(日)12:08 ID:veJK4T2Q(1/3) AAS
返却された値がスタック上でどう扱われるかというのは言語仕様でなく最適化の問題だから、そこはRustではなくLLVMの話
言語仕様としては「Rustではタプルを簡単に作れる」「タプルの中身を別々の変数に束縛できる」というだけ
多値返却の目的からすればこれで十分だし、多くの言語はこれに相当する
Goは本当に多値返却という仕様で、これはタプルを返すのとは違う
そもそもタプルが言語仕様になくて、関数の返り値でだけ多値を返せるという変わった仕様
だから、2つの戻り値を返す関数を1変数で受け取ることができなかったりする
(Rustでいえば「戻り値を分解せず1つのタプル変数 t で受け取る -> t.0, t.1 のようにアクセスする」という書き方がGoではできない)
だから言語仕様としての話をしたいのか、「関数から複数の戻り値を返す」という目的の話をしたいのかで話は変わる
後者については、最近の多くの言語ではサポートしてるし、そんなに話がズレることもない
前者の意味でなら、Rustは多値返却の構文を持つ言語とは違う
48: 08/24(日)12:16 ID:aQdKZ7zp(1) AAS
Goの多値とRustのタプルは同じ
どちらも実装は多値として返すため多値レジスタ返しが可能ならばそうするため効率が最も優れている
関数定義もほぼ同じ
func foo() (type1, type2) {…
fn foo() -> (type1, type2) {…
49(1): 08/24(日)12:16 ID:tCu5AZNy(1) AAS
バカなやつほど抽象度の区別ができない
バカなやつほどオレオレ定義で用語を使う
バカなやつほど主語を書かない
本当に相手にする価値があるか考えよう
改善の見込みがないバカなら何を書いても時間の無駄でしかない
50: 08/24(日)12:26 ID:95hjiUrq(1) AAS
多値を抽象化して機能を強化したものがタプルだもんね
だから多値でできることは全てタプルでもできるんだよ
タプルを持つ言語は機能の低い多値を別途持つ必要がない
51(1): 08/24(日)12:50 ID:veJK4T2Q(2/3) AAS
「タプルがあれば十分」は殆どのケースでは同意するけど、Goに限ってはそうする理由があるんだよ
エラーを多値で返す仕様かつ、エラー処理を明示的に書かせる思想の言語だから
value, err := foo()
のように err がコード上に表れるようにする必要があって、これはタプルだとまずい
t := foo() と書けてしまうと「タプルの2要素目がエラー」というのが見えなくなる
これは割とGo特有の事情で、Result型や例外を使う言語だとタプルでも困らない
言語仕様というのは他の部分も含めた全体的なデザインとして考えるものだから、「Rustではタプルで困らない」が正しくても、他の言語含めて全てそうだとは言えない
52: 08/24(日)12:56 ID:9a3ehhoR(1) AAS
>>49
>バカなやつほど抽象度の区別ができない
>バカなやつほどオレオレ定義で用語を使う
>バカなやつほど主語を書かない
汚コーダーの特徴が濃縮されてるね
3番目は「書かない」というより「書けない」だと思う
53: 08/24(日)13:02 ID:LAWD3p/v(1) AAS
原始的な剥き出しの多値を扱う必要のない言語においては、タプル多値があれば多値をサポートしているという結論でいいんじゃないかな
54(1): 08/24(日)13:07 ID:vekMbO+E(1) AAS
Rustはnamed tupleもanonymous structもなくunnamed tupleで位置でアクセスするか事前に定義した型で名前でアクセスするかしかないから利便性ではモダンな他言語に一段劣る
55(3): 08/24(日)13:18 ID:kBf9AmUd(1) AAS
>>54
これ便利だと思う?
# まずnamedtuple関数をインポートします
from collections import namedtuple
# 次にNamed Tupleを定義します
Point = namedtuple('Point', ['x', 'y'])
# そしてインスタンスを作ります
p = Point(10, 20)
# 名前でアクセスできるようになります
print(p.x) # Output: 10
print(p.y) # Output: 20
56(2): 08/24(日)13:28 ID:fUN48E4b(1/2) AAS
>>51
いや、エラーに限らずt.0とか普通に可読性最悪だからね
多値をタプルとして実装するなら、即時の分割代入を必須とするか、もしくはC#のようにpositionalなタプルと互換性のあるnamed tupleとするか、どちらかは必須
57: 08/24(日)13:41 ID:uDNIRrgr(1) AAS
必要となるまでは1つのまとまりとして一括して扱えたほうが有利
必要になったところでパターンマッチングさせて個別に用いる
58: 08/24(日)13:49 ID:+tDfyqBW(1) AAS
Rustは必要なところではパターンマッチングできるから不便なことはないよな
59(1): 08/24(日)13:56 ID:fUN48E4b(2/2) AAS
取得から消費までのコード上の距離が離れるほど人間の短期記憶の負担になり可読性が低下する
複おじは特に頭悪いから実感してるんじゃない?
60(1): 08/24(日)14:11 ID:0UxuBUhy(1) AAS
let (unko, chinko) = unkochinko
とか突然出てきてunkochinkoの宣言が離れてたら、合ってるのか不安を感じてつい宣言までスクロールしちゃうわ
離れた場所での位置依存は普通に可読性最悪
上下前次1-新書関写板覧索設栞歴
あと 169 レスあります
スレ情報 赤レス抽出 画像レス抽出 歴の未読スレ
ぬこの手 ぬこTOP 0.018s