Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(指定なし : 指定なし)
Re:プロシージャの使い方のバルバロッサさんへ
投稿日時: 17/01/10 16:36:56
投稿者: mattuwan44

>そして,引数と戻り値です.なんだか,どこまでを戻り値と考えるかの定義(うまく書けませんが..)が
>よく分かりません.

  
既存の関数を参考にすればよいのでは?
  

Sub test01()
    MsgBox orgGetSum(Range("A1:A5"))
End Sub

Function orgGetSum(ByVal Rng As Range)
    Dim i As Long
    Dim t As Double
    
    For i = 1 To Rng.Count
        t = t + Rng(i)
    Next
    orgGetSum = t
End Function


Sub test02()
    MsgBox Left("abcd", 2)
End Sub


Sub test03()
    Dim i As Long
    
    i = Rnd * 5
    
    MsgBox Choose(i, "a", "b", "c", "d", "e")
End Sub

 
  
今回参考にしたのは、Choose関数。
  
Choose関数の反対の関数があればいいのに、、、というところから作りました。
  
オブジェクトブラウザでChooseを検索すると、
  
Function Choose(Index As Single, ParamArray Choice() As Variant)
    VBA.Interaction のメンバー

 
と出るので、同じように引数の宣言をしてみました^^
  
>始めに書いたようなプロシージャを使わない長いプログラムになってしまったのかと思います.
どだろ?こういうのは慣れじゃないですかね?
最初から共通化できる部分があるかも?なんて考えないです。
  
でも、もっと大まかに考えますかね?
  
メインのプロシージャ
行毎の繰り返し
5列目と31列目と32列目を見て何通りあるパターンの何番目か判定する
パターン番号毎に数える
次へ
シートに書き出す
プロシージャ終わり

 
  
だいたいの流れを考えたら、
今度はその下流を個別に考える
  
function 判定する関数(値1、値2、値3)as long
n1=リストの何番目(値1、array(N2,N3,R))
n2=リストの何番目(値2、array(34,35,36,37))
n3=リストの何番目(値2、array(24,25,26,1000))
判定する関数=n1 * 36 + n2 * 6 + n3
関数プロシージャ終わり

 
  
function リストの何番目(vItem As Variant, ParamArray vList() As Variant)as long
    ’省略
関数プロシージャ終わり

  
function パターン番号毎に数える(パターン番号 as long) '返り値なし(配列変数に直接上書き)
  '省略
関数プロシージャ

  
こうやって分けると、いいのかなぁと思います。
Function

Sub
の使い分けは、
結果に値が欲しいとき、Function
結果に操作が欲しい時、Sub
じゃないかなぁ。。。。
  
あとは、
いいアイデアが出るか出ないかの各人のセンスです^^
道具は揃ってます、上手く使いこなせるといいですね^^

回答
投稿日時: 17/01/12 06:19:20
投稿者: 佳

こんにちは。
mattuwan44さんが新スレを建ててくださったので便乗させていただきます。
 
 
 
バルバロッサさん
それでどこで引っかかっておられるか考えてみました。
FORTRANのことは何も知りませんので、見当違いでしたら失礼。
 
VBAでは変数は基本的にlocalです。globalではありません。
これはVBAの文化です。また暗黙の了解事項です。
掲示板での説明でも入門書でもlocalを前提に書かれています。
 
また、VBAではサブプロシージャ・ファンクションプロシージャの引数は値渡しが基本です。
じつは何も指定しなければ参照渡しになるのですが、にもかかわらず、わざわざ
byval の指定をしてまでも値渡しが基本です。
これはVBAの文化です。また暗黙の了解事項です。
掲示板での説明でも入門書でも値渡しを前提に書かれています。
 
こういった文化の違いが理解を妨げているのかな、と考えますがいかがでしょう?

回答
投稿日時: 17/01/12 22:59:44
投稿者: simple

私からもバルバロッサさんの発言
> そして,引数と戻り値です.なんだか,どこまでを戻り値と考えるかの定義
> (うまく書けませんが..)がよく分かりません.
についてコメントしておきます。
 
あなたの疑問は、

Sub SelectC(iCol As Long, iAns As Long) 
という定義をしておき、
iCol = WB(1).Worksheets(1).Cells(n, 31).Interior.ColorIndex 
Call SelectC(iCol, iAns) 
cBe = iAns 
と書いても、計算結果が"戻っている"ではないか、なぜいけないのか、
というものでしょう。
 
これについて説明しておきましょう。
 
たしかにこれで計算結果が戻っています。得られています。
しかし、これは余り一般的な書き方ではありません。
 
通常は、Functionプロシージャを用いて、明示的に戻り値を利用します。
 
(1)ワークシートにユーザー定義関数を置いて利用することはありませんか?
   まさにあれと同じ形式のほうが分かりやすいのではないかと申し上げました。
 
(2)つまり、VBAのコード中でも、値を計算するときは同じです。
 
  Call 合計(x,y) 
として x (例:複数のセル範囲)の合計を y に戻すより、
   y = 合計(x)  
と書く方が、直感的に分かりやすいだろう。
   ということです。分かりますか?
 
(3)貴兄のような形式を使うことがないわけではありません。
   ある種の WindowsAPIを呼ぶ場合に、
   z = 関数(x1,x2,y)
   のように、
   ・処理の成否 z(例:成功は1,失敗は0) を 関数の明示的戻り値とし、
   ・処理の結果そのものは、渡した引数 y を修正する形で戻す
   方式を使うケースが見られます。
   ただし、こうした形式は、APIで決められているため、
   ユーザーには選択の余地がないわけです。こうするほか無いのです。
 
(4)繰り返しますが、
  ・貴兄の方式(暗黙の戻り値を引数に指定する方式)も使えます。
    処理結果のステータス(成功、エラー値等)の他、
    成功した場合の返り値など、複数の情報を返すような場合に使います。
  ・しかし、今回のような入力が一つ、答えもひとつのような単純なケースでは、
   (ユーザー定義関数のような)明示的な戻り値を使う方が普通だ、ということです。
 
-----------------------
以下は、少し脇道に逸れます。
 
> また、VBAではサブプロシージャ・ファンクションプロシージャの引数は値渡しが基本です。
というコメントがありました。
> じつは何も指定しなければ参照渡しになるのですが、にもかかわらず、わざわざ
> byval の指定をしてまでも値渡しが基本です。

私見ですが、この説には賛成しかねる感じです。
上記の(2)のことをこうした形で言及されているのかもしれませんが、
「値渡しが基本」とまでは言えないんじゃないでしょうか。
 
(a)
田中さんのサイトにある「参照渡しと値渡し」にも
http://officetanaka.net/excel/vba/tips/tips94.htm
値渡しが基本といった記述はありません。
> どのやり方が最も優れているか…ということではなく、
> ケースに応じて適切な方法を使い分けるようにしましょう。
とあるだけです。
 
(b)
VBAに付属のヘルプの
「引数の効率的な引き渡し」
にも値渡しが基本といった記述は見られません。
 
むしろ、値渡しについては、コピーのオーバーヘッドを考慮して、
文字列やVariant型では、参照渡しを推奨しているほどです。
> プロシージャを宣言するときにキーワード ByVal を指定すると、
> 引数を値渡しで渡すことができます。値で渡される引数は、
> 引数のデータ型に応じて、プロシージャ内で 2 〜 16 バイトのメモリ領域を使用します。
> データ型が大きいほど、値渡しに要する時間が少し長くなります。
> このため、一般に文字列型 (String) とバリアント型 (Variant) では
> 値渡しを使用せず、参照渡しを使用します。

(c)
確かに、渡した引数に操作を加えることによる副作用は減るかもしれませんが、
プロシージャ内で引数に修正を加えない場合にそのリスクはないし、
オーバーヘッドも考慮すると、必ずしも値渡しにするのが好ましいとまでは
言えないんじゃないかと思います。
 
この掲示板を読まれた方が、
すべての引数にByValをつけないといけないんだと解釈されると、
それはそれで困ったことにならないのかなあ、と思いました。
 
いや、やっぱりByValと書くべきだという意見もかたも、どうぞ主張なさってください。

回答
投稿日時: 17/01/14 09:02:34
投稿者: MMYS

佳 さんの引用:
また、VBAではサブプロシージャ・ファンクションプロシージャの引数は値渡しが基本です。
じつは何も指定しなければ参照渡しになるのですが、にもかかわらず、わざわざ
byval の指定をしてまでも値渡しが基本です。

simple さんの引用:
「値渡しが基本」とまでは言えないんじゃないでしょうか。
 

私は、VBAは参照渡しが基本だと思います。
経験上、プロシージャ内での引数の値の書換えが必要なことはほとんどありません。
また、必要なときは、新たにローカル変数を定義して引数を代入すれば良いだけです。
必要無いのに、実行スピードを犠牲にして値渡しにするメリットは無いと思います。
 
重要なことはプロシージャ内で引数の値を書換えてはいけない。ということを理解することです。
 
 
逆にこの特性を意図的に使って、2つ以上の戻り値を呼び出し元に返すことが出来ますが、
バグの原因になるので少なくとも初心者のうちは使うべきではありません。
 

回答
投稿日時: 17/01/14 10:40:07
投稿者: 佳

こんにちは。
 
どうもわたしの日本語がまずくて誤解を招いたようです。
値渡しが基本とは、それが良いとか 正しいとか 推奨とか
そういった事を言っているのではなく、
 
バルバロッサさんがプロシージャについて勉強されるときに
入門書、入門サイト等を読まれるとき
なんの言及もなければ筆者は値渡しを念頭に書いているので
読むほうもそのつもりで読んでくださいね、
という意味です。
 
筆者が念頭にというか、読者のほうが
初めてプロシージャに触れるとして
たとえば数値を2倍して返すコードの解説を読むときに
参照渡しを当然の前提として読むことはないので
筆者もそれに合わせるわけです。
 
わたしはFORTRANのことを知りません。
根拠もなく、エライひとが使うものというイメージがあります。
前スレでバルバロッサさんが出されたプロシージャのコードを見て、
もしかしたらそちらの世界では参照渡しが当然の前提なのかな?
と考えました。
 
バルバロッサさんは、プロシージャについてご自分なりに勉強されているようです。
そのうえでうまく理解できない。ならば、普通に勉強して目にするような回答では
たぶんお役に立たないだろうと考え、
もしかしたら前提としている世界観が違うのではないですかとコメントしてみました。
これで違う世界が見えて理解が進んでくれればラッキーですが、うまくいかなければ
さらにべつの回答をなにか考えなくちゃです。
 

回答
投稿日時: 17/01/15 19:55:09
投稿者: simple

私も、質問者さんが最後に発したひと言に、
別にムキになることもないわけです。
たぶん理解はされたんだろうと思っています。
反応がないので、少し残念ですけどねえ。
 
佳さんの、質問者さんに向けて助言されるお気持ちも理解している積もりです。
ただ、事実として少し違うんじゃないかな、というところがあり、
くどいですけど、コメントします。
 
(1)
どうも、
「引数に戻り値を受ける方式を採らない」ことと、
「値渡し」とを同一視して、こうした方式にすべき、とか、
これが基本だとかおっしゃっているところが、少しひっかかります。
 
「引数に戻り値を受ける方式」と
「参照渡し」を同一視されているようですが、
「参照渡し」をしないと「引数に戻り値を受ける方式」が採れないことは事実ですが、
『「参照渡し」で、かつ「引数を渡すだけ」』ということもあるのをお忘れ無く。
というより、実際にはこうした使い方が一番多いんじゃないですか?
 
(2)
> 入門書、入門サイト等を読まれるとき
> なんの言及もなければ筆者は値渡しを念頭に書いているので
> 読むほうもそのつもりで読んでくださいね、
> という意味です。
>
> 筆者が念頭にというか、読者のほうが
> 初めてプロシージャに触れるとして
> たとえば数値を2倍して返すコードの解説を読むときに
> 参照渡しを当然の前提として読むことはないので
> 筆者もそれに合わせるわけです。
 
 今日、買い物のついでにVBA関連の書籍を見てきましたが、
入門書が多いせいか、あまり渡し方に触れた本はありませんでした。
もちろん、プロシージャの引数にすべて ByValをつけていた本は皆無でした。
省略しているので、参照渡しになっているのです。
 
「筆者は値渡しを念頭に書いている」と言うより、
「それには触れない、説明する必要がない」という立場でしょう。
もし値渡しと思って省略(すなわち参照渡しです)しているのなら、
それは書籍の著者として失格でしょう。
(まあ、そうした人も多いかもしれませんが)

回答
投稿日時: 17/01/19 07:04:28
投稿者: 佳

こんにちは。
なかなか時間が取れないので、手短になります。
 
(1)バルバロッサさんは理解していないと見ています。
 ただ、どこでひっかかっておられるかが分かりません。
 なのでわたしには、どうするべきとか確定的に言えません。
 いまは問題点を探りたい段階で、極端に言えば、正しい情報の伝達を考えていません。
 
(2)おっしゃるとおりです。訂正します。
 入門書では、あたかもメモリーが存在しない世界で 値が受け渡しされているかのような
 書き方になっています。
 
 
 
おかげさまで、ひとつ啓示がありました。
いままでファンクションプロシージャが結果を返す、というのがピンと来ないというか
自分の言葉になっていなかったのですが、ふと
「関数そのものがマップされていたメモリに、計算結果を残して自分は消える」
というイメージが浮かびまして(チェシャ猫みたいだ。。。
「いやいや、いくらなんでもそれは乱暴だろう」ということで
「計算結果をメモリに格納し、そのアドレスを渡す」と。
もしくは、呼び出しもとの指定するアドレスに計算結果を格納する。
微妙に違うかもしれない、、、、少し調べてみます。
 

トピックに返信