今回、Iteratorの.map()
等の例外処理に苦戦したので、それを通してIteratorのメソッドの実行タイミングについて書き残します。
この記事ではTypeScriptを使っています。
JavaScriptを使っている人は
頑張って型宣言を外してください。
Iteratorとは?
イテレータープロトコルに準拠するオブジェクトで、色々とメソッドがあって便利です。
TypeScriptではIteratorObject<T>
にあたります。
(Iterator
だとイテレータープロトコルになる)
このオブジェクトを返すメソッドが意外と多く、
Array.values()
やMap.keys()
、Set.values()
など色々とあります。
(こちら.prototype
が省略されています)
失敗するサンプルコード
function addSamaToNames(names: IteratorObject<string>){
return names.map(e => {
if(e.toLocaleLowerCase() === "google")
throw new Error("生理的に無理です");
return `${e}様`; // 豪華にテンプレートリテラルを使う
})
}
const names = new Set<string>();
names.add("Microsoft");
names.add("Microsoft");
names.add("Microsoft");
names.add("Qiita");
names.add("Microsoft");
names.add("GitHub");
names.add("Yahoo");
names.add("Google");
try{
var samas = addSamaToNames(names.values());
}catch{
// addSamaToNamesでのエラーはここで受け止めたい
throw new Error("ブロックされました。");
}
console.log(samas.toArray().join("、"));
こちら、try-catch文の所で、addSamaToNames
の
names.map
のコールバックが投げる生理的に無理です
という本音を隠して
例外を投げてほしいのですが、なぜかconsole.log
の段階で例外が発生してしまい、
本音が漏れてしまいます。
なぜ失敗する?
なんと、これらイテレーターのメソッドは遅延的に計算するんです。
遅延的というのは、.map
をした時点では実行されず、.toArray
などで必要になった際計算する仕組みのことです。
これのおかげで無限イテレーターに.map
を使えるそうです。
そのため、addSamaToNames
のnames.map
の時点では例外が起こらず、
toArray
の時に計算してしまい他の所で例外を解き放ちます。
対処法
ただ単に、そのメソッド内でtoArray()
をするだけです。Array.from()
も可。
function addSamaToNames(names: IteratorObject<string>){
return names.map(e => {
if(e.toLocaleLowerCase() === "google")
throw new Error("生理的に無理です");
return `${e}様`; // 豪華にテンプレートリテラルを使う
}).toArray();
}
// ~~~
console.log(samas.join("、"));
以上です。誰かの役に立てますように。