بخش چهارم
• دستور for…in
مایکروسافت ویژوال بیسیک دستوری برای پیمایش از ابتدا تا انتهای یک مجموعه دارد که for..each نامیده میشود. قبلا" چنین ایده ای
در #C نیز پیاده شده است. شرکت بورلند در دلفی نسخه 2005 تصمیم گرفت که پشتیبانی بهتری از این نوع کد را انجام دهد. البته نه فقط برای کامپایلر دات نت بلکه هم برای کامپایلر Win32 و هم برای دات نت. الان این دستور برای استفاده آماده است، البته نه تنها برای یک کلاس Container بلکه برای :
- کاراکترهای موجود در یک رشته
- مقادیر یک مجموعه
- آیتم های یک آرایه داینامیک یا استاتیک ، شامل آرایه های دو بعدی
شکل کلی :
For element in collection do
به مثال های زیر توجه کنید :
- کاراکترهای موجود در یک رشته
var
s: String;
ch: char;
begin
s := 'Hello world';
for ch in s do
ListBox1.Items.Add(ch);
end;
در این مثال، حلقه به تعداد ch های موجود در s اجرا خواهد شد، یا به عبارتی حلقه به تعداد کاراکترهای موجود در s اجرا میشود.
- آیتم های یک آرایه
var
iArray: array[1..5] of integer;
i: integer;
begin
iArray[1] := 1;
iArray[2] := 2;
iArray[3] := 3;
iArray[4] := 4;
iArray[5] := 5;
for i in iArray do
ListBox1.Items.Add(IntToStr(i));
End;
در این مثال، حلقه به تعداد i موجود در iArray تکرار خواهد شد. اگر فرضا" برای دو خانه آخر آرایه مقداری در نظر نگیرید ، چون آرایه به صورت استاتیک تعریف شده، باز هم حلقه 5 بار تکرار خواهد شد که در مورد آرایه های داینامیک ، به خاطر ماهیتشان، چنین اتفاقی نمی افتد.
- مقادیر یک مجموعه
type
TNumber = (one, two, three);
TNumberSet = set of TNumber;
var
Number: TNumberSet;
myNumber: TNumber;
begin
Number := [one, two, three];
for myNumber in Number do
// do something
Number := [one, three];
for myNumber in Number do
// do something
end;
در این مثال، حلقه به تعداد عنصرهای موجود در مجموعه تکرار میشود، یعنی برای حلقه اول 3 بار و برای حلقه دوم 2 بار.
procedure TForm1.Button2Click(Sender: TObject);
var
c: TComponent;
begin
for c in self do
ListBox1.Items.Add(c.Name);
end;
در این مثال، حلقه به تعداد کامپوننتهای موجود در فرم اجرا خواهد شد و نام آنها را به لیست اضافه خواهد کرد.
• Advanced Record
رکوردها همیشه بخشی از زبانهای برنامه نویسی هستند. اما در این نسخه به رکوردها میدان بیشتری داده شده چونکه از این به بعد برای رکورد میتوان هم "متد" تعریف کرد و هم از مفهوم نهان سازی یا Encapsulation استفاده کرد ( البته فقط از public و private).
یک رکورد به همراه متد تا حدی شبیه به یک کلاس است. بیشترین تفاوت (به غیر از مفاهیم Inheritance و Polymorphism) این است که :
رکورد از حافظه محلی (از Stack frame) استفاده میکند.
رکورد را میتوان به عنوان پارامتری از نوع By Value ارسال کرد.
رکورد در زمان تخصیص یک متغیر رکورد به یک متغیر رکورد دیگر رفتار "value copy" دارد. به این معنی که محل دیگری از حافظه با محتویات رکورد مبدا مقدار دهی میشود.
از کلمات کلیدی مانند dynamic و virtual و message در تعریف رکورد نمی توانید استفاده کنید.
در مقابل متغیری از نوع کلاس :
در حافظه Heap قرار میگیرد.
به عنوان پارامتر به صورت By Reference ارسال میشود.
در هنگام تخصیص یک متغیر کلاس به یک متغیر کلاس دیگر رفتار "reference copy" دارد. به این معنی که متغیر مقصد هم به همان محل از حافظه اشاره میکند که متغیر مبدا اشاره میکند، در واقع عمل "کپی" صورت نمی گیرد بلکه آدرس حافظه به متغیر مقصد تخصیص داده می شود.
برای مثال :
وقتیکه متغیری از نوع رکورد تعریف میکنید ، متغیر مربوطه در Stack ایجاد میشود و میتوانید بلافاصله از آن استفاده کنید .یک متغیری از نوع رکورد نسبت به متغیر نوع کلاس کمتر به سمت مدیر حافظه و Garbage Collector میرود.
Type
TpersonInfo: Record
Fname: String;
Lname: String;
End;
Var
myInfo: TpersonInfo;
در این حالت ، به محض تعریف متغیر myInfo از نوع TpersonInfo ، محلی از حافظه به myInfo اختصاص داده میشود و میتوانید از آن استفاده کنید. در صورتیکه در مورد کلاس این مراحل یک قدم اضافه میشود :
Type
Tfoo = Class
End;
Procedure DoIt;
Var
myFoo: Tfoo;
Begin
myFoo:= Tfoo.Create(Self);
End;
اینها دلایل کلیدی برای استفاده از Record به جای Class هستند.
رکورد میتواند یک Constructor نیز داشته باشد، اما این Constructor حتما" باید یک پارامتر داشته باشد ، در غیر اینصورت پیغام خطای "parameterless constructors not allowed on record types" را دریافت می کنید. چرا بورلند این شرط را لازم دانسته است؟ رکورد به طور خودکار ساخته میشود ، یعنی یک constructor بدون پارامتر دارد، پس زمانی که برنامه نویس ، constructor دیگری تعریف میکند، باید یکی یا بیشتر پارامتر نیز برای آن در نظر بگیرد تا تفاوتی بین constructor پیش فرض و constructor یی که برنامه نویس تعریف کرده بوجود بیاد.
نمونه :
تعریف :
TmyRecord = Record
Private
one: string;
two: integer;
three: char;
public
procedure print;
constructor Create(aString: string);
procedure Init(aValue: Integer);
end;
پیاده سازی :
procedure TmyRecord.Print;
begin
showmessage (one, ' - ' , two, ' - ', three);
end;
constructor TmyRecord.Create(aString: string);
begin
showmessage ('TMyRecord.Create called');
one := aString;
two := 2;
three := '3';
end;
procedure TmyRecord.Init(aValue: Integer);
begin
two := aValue;
one := IntToStr (aValue);
end;
استفاده :
var
myrec: TmyRecord;
begin
myrec := TmyRecord.Create('hello');
myrec.Print;
end;
وقتی در این زبان برنامه نویسی کلاس وجود دارد، مطمئنا" تعجب می کنید که چه دلیلی دارد که رکورد "متد" داشته باشد ؟ گذشته از کمبود ویژگیهای جدید و پیشرفته در کلاس، فرق اصلی بین رکورد و کلاس، روش استفاده آنها از حافظه ست.