程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 推遲調用以及Lambda表達式,推遲lambda表達式

推遲調用以及Lambda表達式,推遲lambda表達式

編輯:C++入門知識

推遲調用以及Lambda表達式,推遲lambda表達式


背景

GMock

我們項目中現在的模塊測試框架使用了CATCH+GMock的方式實現回歸測試和打樁。

GMock的介紹在官網上有,這裡為了鋪墊,大概地描述一下GMock能實現的效果。大約可以看成這樣:

  1. void A() {
  2.     if(B()) {
  3.         //...
  4.     }
  5.     Else{
  6.         //...
  7.     }
  8.  
  9. }

A是被測函數,B是樁函數。

在測試的,使用GMock的話,我們可以這樣寫測試代碼:

  1. TEST_CASE(Test As normal case) {
  2.  
  3.     EXPECT_CALL(mockobj, B).times(1).WillOnce(Return(true)); // MockBAtrue
  4.  
  5.     A(); // A
  6.     // BFailedB should be called but not called
  7.  
  8. }

模塊測試

所以,使用GMock以後我們可以很愉快地打樁了,但是有一個問題是,必須在調用被測函數 (A)之前給B函數打樁(描述B應該被調用幾次,以及有什麼樣的行為)。這在UT中雖然是沒有什麼問題的(因為UT中函數只調用一次),但是要是用在模塊的時序測試上,就會使人產生時序上的混亂感。

比如我們有一個時序:

   

Tester  ---Msg1-–> B
                         B call IF1
                         B call IF2

Tester  ---Msg2-–> B
                         B call IF3
                         B call IF4

我們如果正常地按時序思路寫測試代碼,那麼希望是這樣的(Program1):

  1. TEST_START()
  2.  
  3. SendMsg(toB, msg1);
  4. IF1_isExpectedTobeCalled(Mock)
  5. IF2_isExpectedTobeCalled(Mock)
  6.  
  7. SendMsg(toB, msg2);
  8. IF3_isExpectedTobeCalled(Mock)
  9. IF4_isExpectedTobeCalled(Mock)
  10.  
  11. TEST_END()

但是,由於GMock的使用方法決定,我們必須先寫成這樣:

  1. TEST_START()
  2.  
  3. IF1_isExpectedTobeCalled(Mock)
  4. IF2_isExpectedTobeCalled(Mock)
  5. SendMsg(toB, msg1);
  6.  
  7. IF3_isExpectedTobeCalled(Mock)
  8. IF4_isExpectedTobeCalled(Mock)
  9. SendMsg(toB, msg2);
  10.  
  11. TEST_END()

在很長的時序和很多的樁的情況下這就顯得很別扭了。編寫和維護的時候都很容易出錯。

問題

能不能提供一種辦法(宏),使得我們可以像(Program1)那樣的順序寫代碼,

同時,代碼又是以Program2這樣的順序來執行呢?(即,書寫時按我們的正常思路寫,執行時,按GMock需要的順序執行)

比如:寫代碼時可以這樣:

  1. TEST_START()
  2.  
  3. TEST_STEP(SendMsg(toB, msg1))
  4. IF1_isExpectedTobeCalled(Mock)
  5. IF2_isExpectedTobeCalled(Mock)
  6.  
  7. TEST_STEP(SendMsg(toB, msg2))
  8. IF3_isExpectedTobeCalled(Mock)
  9. IF4_isExpectedTobeCalled(Mock)
  10.  
  11. TEST_END()

而實際的執行順序是:

  1. IF1_isExpectedTobeCalled(Mock)
  2. IF2_isExpectedTobeCalled(Mock)
  3. SendMsg(toB, msg1);
  4.  
  5. IF3_isExpectedTobeCalled(Mock)
  6. IF4_isExpectedTobeCalled(Mock)
  7. SendMsg(toB, msg2);

 

解法

中間我自己的折騰過程總不詳細描述了,實際上我們就是要實現推調用的效果,而且,由於我們知道調用需要推遲到哪個點,那麼非常容易想到“析構函數”,因為析構函數會在作用域結束時被調用。所以我們如果可以把函數調用存儲在一個對象裡,然後讓這個對象在指定的點析構,析構時調用我們之前存儲的函數,目的就達到了。問題是“函數”如何存儲。答案就是C++11中提供的function庫和lamabda表達式,實現方法如下:

  1. class CallLater {
  2. public:
  3.     CallLater(function<void(void)> _fun): m_fun(_fun){
  4.  
  5.     }
  6.  
  7.     ~CallLater() {
  8.         m_fun();
  9.     }
  10. private:
  11.     function<void(void)> m_fun;
  12. };
  13.  
  14.  
  15. #define TEST_STEP(fun)  } { CallLater temp ([](){ fun; });
  16. #define TEST_START()     {
  17. #define TEST_END()       }

相當地簡潔和舒服。這就是為什麼我非常喜歡C++11中的那些“語法糖”。


lambda表達式不懂,舉個簡單的例子,再解釋一下,

最大的作用是用在匿名函數和linq查詢上。
這是用在匿名方法上的:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
等價於
delegate int del(int i);
del myDelegate = delegate(int i){i=i*i;};
int j = myDelegate(5); //j = 25
至於linq前景不明,就不要深究了。

直接i+1???
呵呵,你是沒碰到一些必須用委托的情況。
比如跨線程調用,你只能用委托,而lambda表達式就是一個很方便的寫法。純粹為了方便而已。
 

lambda表達式來自什地方?

Lambda表達式(Lambda Expressions)2009-03-06 16:33Lambda 表達式(拉姆達表達式) 和 匿名方法 其實是一件事情。唯一的不同是:他們語法表現形式不同。Lambda 表達式是在語法方面的更進一步的進化。在本質上,他們是一件事情。他們的作用都是:產生方法。即:內聯方法。

引用自 C#首席架構師Anders Hejlsberg 的原話:

www.ondotnet.com/...page=2

lambda expressions and anonymous methods are really just two words for the same thing. The only thing that differs is, "What does the syntax look like?" And the lambda expressions are a further evolution of the syntax.But underneath, they do the same thing. They generate methods. You know, they're in-line methods.

所以:我們要了解 Lambda 表達式 就應該同時也了解 匿名方法。下面先看一個簡單的代碼例子,分別用匿名方法和Lambda 表達式來實現對數組的搜索:

使用 .net 2.0 的匿名方法來搜索字符串數組中包含 a 的字符串數組

static void Main(string[] args)
{
string[] list = new string[] { "abc", "12", "java" };
string[] ll = Array.FindAll(list,
delegate(string s)
{
return s.IndexOf("a") >= 0;
}
);
foreach (string var in ll)
{
Console.WriteLine(var);
}
Console.ReadLine();
}

使用 .net 3.5 的Lambda表達式來搜索字符串數組中包含 a 的字符串數組

static void Main(string[] args)
{
string[] list = new string[] { "abc", "12", "java" };

string[] ll = Array.FindAll(list, s => (s.IndexOf("a") >= 0));
foreach (string var in ll)......余下全文>>
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved