★独学者が1年後にExcelVBAを爆発的に伸ばすための最低限の基礎知識メモ(ダイジェスト):Vol0026:ついでに、ウォッチウィンドウの「一般的に、普通に使う使い方」も少し-09。(エラー回避の基礎10)★変数宣言で「LET」を使う方法についてと「SET」との比較、および、「UsedRange」について調べる。
  
バックナンバー目次ページは→こちらです。

まぐまぐのページは以下です。
https://www.mag2.com/m/0001691660.html
  
  
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■独学者が1年後にExcelVBAを爆発的に上達させるための最低限の基礎知識メモ(ダイジェスト)

Vol.0026

タイトル:ついでに、ウォッチウィンドウの「一般的に、普通に使う使い方」も少し-09。(エラー回避の基礎10)

★変数宣言で「LET」を使う方法についてと「SET」との比較、および、「UsedRange」について調べる。
  
  

バックナンバー目次とサンプル号
https://euc-access-excel-db.com/tips/ct07_se/ct075012_xls2k_vba_tips/mag2-01

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  

今回も前回の続きです。

途中になってしまっていてすみませんが、

以下のプログラムの続きでした。

  
  

で、まずは、

上記のコードの「ggg = ActiveSheet.UsedRange」の先頭に、

「Let」

という命令語句を書き足して下さい。

「Let ggg = ActiveSheet.UsedRange」

となります。
  

それからその次の行に、(つまり「Stop」の前に)、

「Set rrr = ActiveSheet.UsedRange」

というコードを1行、書き足してください。
  

あと、変数宣言の箇所(「 Dim ggg As Variant」 の次あたり)にも、

Dim rrr As Object

という宣言を増やしてください。

  

そして、Sheet1をアクティブにして、

A列とB列に上から順に

a,b
1,4
2,5
3,6

と値を入力してください。

下図のようになります。

  

で、今回は、

「ActiveSheet.UsedRange」と
「ggg」と
「rrr」の
3つを全部、ドラッグで青色選択してからウォッチウィンドウに放り込みます。

下図のようになります。

  

できましたら、その状態から、いつもどおり、F8キーを繰り返し押して、ステップ実行をします。

そして、

「Let ggg = ActiveSheet.UsedRange」

が黄色になった段階で止めておいてください。

下図のようになります。

  

  

で、ここから説明になります。
  

まず書き加えた「Let」ですが、これは次行や前行の「Set」と関連します。

  

本メルマガでは以前の号で何回も、

『 プログラミングはどんな言語であっても、「操作の対象は」「変数である」』

  (※最終的には変数に代入する生データだけど)

と書きました。

  

そして、VBAの場合、その「変数」を大別すると、

「一般変数(文字系の一般データを代入・格納するための変数)」

「オブジェクト変数(オブジェクト式を代入・格納するための変数)」

の2つしかない、とも書きました。

  
  

今回書き足した「Let」は、そのうちの、

「一般変数(文字系の一般データを代入・格納するための変数)」

に生データを代入する時に使います。

  

多くの場合、省略されてしまうので、本メルマガでも書き忘れてましたが、
本当はこのように「Let」と書かないといけないのです。

  
  

※補足
ここで言っている「一般変数」は、例えば
https://excel-ubara.com/excelvba1/EXCELVBA440.html によると、
「プリミティブな型(基本データ型)の変数」という呼び方をするそうです。
「プリミティブ型」の説明は、
https://wa3.i-3-i.info/word15876.html (ぴよぴよ用語サイト) をご覧ください。
これによると、Variant型はプリミティブではない感じですが、「Let」を使います。

ExcelVBAの神サイトのひとつの以下のページもご参考にしてみてください。
『 VBA LetとSetとCallとカッコ 』
https://thom.hateblo.jp/entry/2015/09/17/123831
『 VBA 用語を正しく覚える ~ステートメントとは 』
https://thom.hateblo.jp/entry/2015/09/12/110436
(VBAエキスパート公式テキスト の説明ミス???)

  

それに対して、
「オブジェクト変数(オブジェクト式を代入・格納するための変数)」
に生のオブジェクト式を代入するときは、「Set」を使います。

  
  

LetとSetできれいにコントラストするので、見た目も「表のようで」きれいなので、今回、せっかくなので使ってみました。

今回のサンプルで言うと、こんな感じに目に飛び込んできます。

  Set ttt = ActiveWorkbook.Worksheets("Sheet1").Range("A1")

  Let ggg = ActiveSheet.UsedRange

  Set rrr = ActiveSheet.UsedRange

「ああ、全部、変数に生データを代入してるところだな」とわかります。

  

基本、日本のExcelVBAの書籍は「省略だらけでいいかげん」とも書きましたが、ここからしてすでに「いいかげん」というわけなのです。

参考URL(他の省略について)

VBAで一番省略されているキーワード


  

「Letなんか付けるの、めんどくせーじゃん」という著者も多いですが、バカなので、そいつらの言うことは聞かなくていいいです。
  

結局「VBA」は、「クラスモジュール」つまり、「=自分独自の自作のオブジェクト」が自由に作れるようにならないと、「本当のところ」は分かりません。
  

なのに、「省略」と称して、そういう「Let」のような「手抜き」を教えるのが、今のVBA教育の風潮です。

『 セル範囲のことを「Range」からいきなり書き始めること 』を、
「本番では絶対に使うな」とか、
「一番エラーの出る書き方」とか、
「何の但し書きもせずに」、
「ね?かんたんでしょ?」と、さも、それが正解であるかのように教えることもです。
  

それらは、「手抜き、ウソを教える」の典型です。
  

『 「ね?かんたんでしょ?」じゃねーわ!ウソ教えやがえって! 』ということなわけです。
  

「手抜き」したら、何も覚えられませんよね。

ましてや「Let」のような基本事項も説明ないなんて、「本当に読者に成長してほしいって思って本書いてるの?あんた?」っていうことなのです。
  

日本のVBAの市販書籍って、このような、『 「省略」と称した「手抜き」』 が多すぎて、ほんとう、あいつら(著者ども)説明のせいで、僕も、ExcelVBAを理解するのに苦労しました。

最初のうちは「信じて」ましたから。
  

僕が上達しはじめたのはあいつらの言うことを「信じなくなって」「ウォッチウィンドウやローカルウィンドウ」を使うようになってから、でした。

  
  

といいつつ、僕も忘れて、使ってませんでした。

反省・・・。

とはいっても、確かに、Letを使うことは非常に多いので、「省略」できると確かに手間が省けます。

悩ましいところですよね。

  

でも、「Let」を書くと、「冗長で無駄」と言う人も居るかもしれませんが、「見た目にきれい」です。また、「ああ、この箇所で変数の代入をしてるな」という風に、「Set」と共に分かりやすいですし。
「Let」があれば、初心者でよくやる「変数の宣言のし忘れ」も見つけやすくなります。
(僕なんていまだにそういうアホなミスをする・・・(^^))

また、変数宣言は、プロシージャの冒頭で、全部の変数を宣言することが多いですが、
場合によっては、その位置でやりたくないとき、つまり、どこか処理の途中で変数宣言をやりたいとき、そういう時なども、「Let」が付けてあると、「ああ、この箇所で変数の代入をしてるな」と、のちのちコードを見直す際にも、見つけやすくなります。

  

それに、

「Letを使った」ということは、

逆に言うと、

「絶対に、オブジェクト変数に代入したんじゃない!この位置では。」
「(場合によっては例えば)自分は間違ってない。」

ということも

「明確」になります。

ですから、「自分が今していること」も明確になり、原因調査や学習を深めるうえで、ものごく明確になって、それがいろんなことに「派生・波及」して、理解が進みやすいとも思います。
  

例えば、これまた、今回の例で言いますと、

  Let ggg = ActiveSheet.UsedRange

  Set rrr = ActiveSheet.UsedRange

の部分でもわかると思います。

2行のコードのそれぞれの変数には、右辺(見かけ上)としては「同じもの」を代入しているように見えます。
ですが、実際は、「Let」と「Set」の部分が異なるので、「見た目としては」似てはいるれけども、「実際に代入されるモノはまるで」「異なる」「非なるモノ」ということなのです。

最初のうちは意味がよくわからなくても、そういう説明を受ければ「たしかにLetとSetが異なるからそういうことなんだろうな・・・」と、なんとなくでも、アタリがつくと思います。

  

なので、初心者のうちは、特に、「オブジェクト変数へのオブジェクト式の代入」の意味がまだよくわかっていないうちは、練習として、「Let」を書くことをおススメします。

  

本当は「クラスモジュール」が自由自在に作れるようになれるまで、「Let」を省略しないほうがいいのかもしれません。

「クラスモジュール」が自由自在に作れる人だけが、「VBAが真に理解できている」と言っても許される人なので・・・。

  

ただ、その「クラスモジュール」が作れなくても、これも以前から何度も言っていますが、

「値(一般データ)、あるいはオブジェクトを返す自作関数が自由自在に作れる人」
「特に、オブジェクトを返す自作関数が自由自在に作れる人」
になれれば、

ヘルプやオブジェクトブラウザも扱えるようになり、「ある地点から」「爆発的に」「上達する」確率が「グンと」上がりますので、ご心配なく・・・・。
  

というわけで、長々とすみませんでしたが、以上、「Let」についての説明でした。

  
  

今回、前置きが超長いです。
  

本当にごめんなさい。
  

次に、ついでに、ですみませんが、「ActiveSheet.UsedRange」の「UsedRange」について少し注意点などをお話しておきます。
https://excel-ubara.com/excelvba4/EXCEL222.html の「UsedRange」の項の受け売りです。

このWebページによると、「UsedRange」のセル範囲には、以下のようなセルが含まれるようです。

(a)値や数式の入ったセル
  (見かけ上空白セルに見えていても、If関数などで空白に見せる
   数式が入っているもの。
   また、非表示行や非表示列でも値や式が入って入れば、そのようなセルも。)

(b)値も数式も入っていないのに、でも、以下のセル
   (c)書式を変更したセル(背景色を付けたり、とか)
   (d)罫線を引いたセル
   (e)行の高さを変更したセル(列幅はいいみたい。)

  
そのようなセルを、「飛び飛びに存在していても」、「全部含む」、「ひろ~い」セル範囲が、「UsedRangeだ」、ということになります。

なので、最終行の数値を取得するときは、「UsedRange」を使う時は注意しないとユーザーが勝手にセルの色や行の高さを変えると、プログラムが誤作動することになります。
(「Worksheet.UsedRange プロパティ」を使うと表の最終行がすごくカンタンに出るのですが)

逆に、「そんなことさせない」という仕組みができていれば、「UsedRange」でテーブル(表)の最終行を取得することは可能となります。

例えばデータベースを良く知っていて、「セルの色や高さなんかいじらん!いじるわけない!」、という人ばかりの職場なら、「割と使える」ということになります。

そうじゃなければ、「Range.CurrentRegion プロパティ」や「Range.End プロパティ」などを使うことのほうが安全だ、ということになります。
ほとんどの場合、ユーザーが画面(セル)をいじる可能性があるので、こちらの方法で処理することになると思います。

だから「Worksheet.UsedRange プロパティ」を使って、最終行を割り出すサンプルってすごく少ないのですね。(巷のほとんどが「Range.End プロパティ」を使うめんどくさいサンプルばっかりです。「Cells(Rows.Count, 1).End(xlUp).Row」みたいな。)

ただ、だからといって、いずれにましても(どの方法でやったとしても)、結局のところ、万能「ではない」ので、「ケースによって使い分けが必要=よく考えて使わないとドハマりする」ので、そこが一般的なデータベースソフトと違う、「Excelのアホなところ・面倒くさいところ」・・・だと思います。

  

そんなところひとつを取ってみても、
「Excelで」
「自分だけが使うプログラムを作るだけならまだしも」、

「他人も一緒にみんなで使うプログラム・ソフト」を作るとき、
「特にデータベース的なソフト」を作るとき、

の、「効率の悪さといったら」、「ハンパじゃない」、と思います。

特にユーザーフォームは、例えばAccessのフォームと比べると、すごくショボいものしかできなく、「ワークシートをフォームに見立てたほうがはるかに便利」、というくらい、「データベース的なデータ共有ソフトを作るときに限っては」「使えない」ので、本当に注意が必要ですね。

外注すれば、それがそのまま「工数の多さ=コストの高さ」、としてハネ返ってきます。
  

しかし、「Value2」プロパティがあるのだから、「Worksheet.UsedRange2 プロパティ」も作って、セルの高さや色がいじられていても関係なく、また、数式が入っていても関係無く、
「とにかく値が表示されたセルの対角線の矩形の範囲の最終行」
を出してくれるプロパティを作ってくれればいいのに、と思ってしまいます。

なぜそうならないか不思議です。
マイクロソフトはサボっている気がします。
  

以上、「UsedRange」を使う時の注意点、でした。

  

  

ではここで「F8キー」を2回押して、「Stop」の位置で止めます。

ウォッチウィンドウが下図のようになります。

  

で、このとき、

「ActiveSheet.UsedRange」と
「ggg」と
「rrr」の

3つともに、「+」マークが付いています。

下図のようになっています。

  

ここで、図にも書いてありますが、

「ActiveSheet.UsedRange」と「rrr」には、両方に「+」マークがあり、「Object/Range」と書かれた部分があるので、

「あ、これはRangeオブジェクトなんだな」

とわかります。

「+」マークを押すと、以下の図のようになって、いろんな「プロパティ」の名前が見えていますので、「あ、やっぱりこれはオブジェクトだな」と明確にわかります。


  
  

ところが、

「ggg」のところには、「+」マークがあるのにもかかわらず、

「Object/××××」

のような記述が見当たりません。

「Variant/Variant(1 to 4,1 to 2)」

となっています。

「+」マークがあるのに、Objectではないようです。

「ggg」とは、何なのでしょうか?

  

・・・というわけで・・・・
  

ごめんなさい!!

説明不足で大変申し訳ございません!
  

この「+」マークは、以前の号で「オブジェクトだよ」とお話させていただきました。

でも、実は、もうひとつ「別のモノ」にも、この「+」マークが付きます。
(まだほかにもあるのかな?)
  

それは「配列変数」です。
  

配列変数のことをまだ学んでない方には大変申し訳ないのですが、配列変数とは、
「複数の変数が集まって、1つの変数であるかのようになった感じのモノ」、です。
単に「配列」とだけ、呼ぶことが多いです。

配列の形態には、
1次元配列(1行だけ、あるいは、1列だけ、のようなイメージの変数)
2次元配列(タテ・ヨコのある表のようなイメージの変数)
3次元配列(ルービックキューブみたいな立体的なイメージの変数)
などがあるのですが、

今回のケースでは、2つめの「2次元配列」というかたちになります。

そしてExcelの場合、配列としての変数宣言をしなくても
「Variant型としての変数さえ用意しておけば」
「その中に、Letで、セル範囲(Rangeオブジェクト)を代入すると」
「勝手に、自動的に、2次元配列になって、そのセル範囲の値が配列変数に自動的に代入され」
「配列のサイズも自動的に決まる」
という風になっています。

この性質を利用すると、セル範囲の値を、セルとの行き来をすることなく、メモリの中で扱えるので、結果、高速に処理ができるようになります。
セルとの行き来をするRangeオブジェクト主体のプログラムの少なくとも100倍以上は、高速に処理できると思います。
また、「WorksheetFunction.Transpose メソッド」を使うと、1行コードでタテヨコの入れ替えができます。
大変に便利です。
  

とはいえ、今回、このような、配列を使ったちょっと難しいことをしてしまいました。

いきなり難しいことをしてしまって申し訳ありませんが、「配列」に関しては、「ふ~ん」くらいで済ませてもOKです。

ただし、Letを使った場合と、Setを使った場合で、「同じようなことをしていても、結果が異なることがある」ということだけは、覚えておいてください。
  

例えば、
「ttt」や「rrr」といった変数には「Set」で代入していますので、
この場合は、変数の中にオブジェクトを代入した・・・ということになります。
そのため、その場合は「配列には」「なりません」。

つまり、同じ「ActiveSheet.UsedRange」を代入しても
「Let」を先頭につけて代入する場合と、
「Set」を付けて代入する場合とでは、
「代入されるモノがまったく異なってくる」
ということになります。

そのこともご説明・・・・というか、さらっと体験だけしてほしたかった、そして、ウォッチウィンドウで実際に確認してほしかった・・・というのがありますので、そのことだけは覚えておいてください。

特にセル範囲(=Rangeオブジェクト)を変数に代入する場合は。

  
  

なお、Letは省略されるので、

Let ggg = ActiveSheet.UsedRange

ggg = ActiveSheet.UsedRange

と書かれることのほうが多いです。

  

でも、本来としては

Let ggg = ActiveSheet.UsedRange

なので、
Letを付けて書くと、

Set ggg = ActiveSheet.UsedRange

とは「別モノだ」ということが明確になるのではないでしょうか?

  
  

逆に「Let」が無いと、何か比較対象になるものがないので、ちょっと見失う=間違うこともあるかもしれません。

そのようなこともあるため、

「クラスモジュールを作れるようになるまで」とか、
「オブジェクト変数の代入について理解が深まるまで」、あるいは
「オブジェクト(特にRangeオブジェクト)を返す自作関数が自由自在に作れるようになるまでは」

「Let」を付けて代入のコードを書いた方がいいかもしれません。

  

  

ではこの「ggg」の「+」マークを展開してみましょう。
下図のようになります。

  

今回、ちょっと余計な説明が多すぎてしまったため、これ以降の詳細は次回に持ち越したいと思います。

毎度、わかりにくい説明ですみませんが、よろしくお願い致します。

  

  
==============================

今回は以上です。

==========================================================================

バックナンバー目次とサンプル号

★独学者が1年後にExcelVBAを爆発的に伸ばすための最低限の基礎知識メモ(ダイジェスト):~バックナンバー~

----------------------------------------------------------------------
■独学者が1年後にExcelVBAを爆発的に上達させるための最低限の基礎知識メモ(ダイジェスト)
発行システム:『まぐまぐ!』 http://www.mag2.com/
配信中止はこちら https://www.mag2.com/m/0001691660.html
----------------------------------------------------------------------