Ví dụ về gotos tốt trong C hoặc C ++ [đóng]


79

Trong chủ đề này, chúng tôi xem xét các ví dụ về cách sử dụng tốt gototrong C hoặc C ++. Nó được lấy cảm hứng từ một câu trả lời mà mọi người đã bình chọn vì họ nghĩ rằng tôi đang nói đùa.

Tóm tắt (nhãn được thay đổi so với ban đầu để làm cho ý định rõ ràng hơn):

infinite_loop:

    // code goes here

goto infinite_loop;

Tại sao nó tốt hơn các lựa chọn thay thế:

  • Nó cụ thể. gotolà cấu trúc ngôn ngữ tạo ra một nhánh không điều kiện. Các lựa chọn thay thế phụ thuộc vào việc sử dụng cấu trúc hỗ trợ các nhánh có điều kiện, với điều kiện suy biến luôn đúng.
  • Nhãn ghi lại ý định mà không có chú thích thêm.
  • Người đọc không cần phải quét mã can thiệp sớm break(mặc dù vẫn có thể cho một hacker chưa có kinh nghiệm mô phỏng continuesớm goto).

Quy tắc:

  • Giả vờ rằng gotophobes không thắng. Người ta hiểu rằng những điều trên không thể được sử dụng trong mã thực vì nó đi ngược lại với thành ngữ đã có.
  • Giả sử rằng tất cả chúng ta đã nghe nói về 'Goto bị coi là có hại' và biết rằng goto có thể được sử dụng để viết mã spaghetti.
  • Nếu bạn không đồng ý với một ví dụ, hãy chỉ trích nó về mặt kỹ thuật ('Bởi vì mọi người không thích goto' không phải là lý do kỹ thuật).

Hãy xem liệu chúng ta có thể nói về điều này như những người trưởng thành không.

Biên tập

Câu hỏi này dường như đã kết thúc ngay bây giờ. Nó tạo ra một số câu trả lời chất lượng cao. Cảm ơn tất cả mọi người, đặc biệt là những người đã coi trọng ví dụ về vòng lặp nhỏ của tôi. Hầu hết những người hoài nghi đều lo lắng bởi việc thiếu phạm vi khối. Như @quinmars đã chỉ ra trong một nhận xét, bạn luôn có thể đặt các dấu ngoặc nhọn xung quanh thân vòng lặp. Tôi lưu ý khi vượt qua điều đó for(;;)while(true)không cung cấp cho bạn niềng răng miễn phí (và việc bỏ qua chúng có thể gây ra lỗi khó chịu). Dù sao đi nữa, tôi sẽ không lãng phí thêm sức mạnh trí não của bạn vào chuyện vặt vãnh này - Tôi có thể sống với những điều vô hại và thành ngữ for(;;)while(true)(cũng như nếu tôi muốn tiếp tục công việc của mình).

Xem xét các phản hồi khác, tôi thấy rằng nhiều người xem gotonhư một thứ mà bạn luôn phải viết lại theo cách khác. Tất nhiên bạn có thể tránh một gotobằng cách giới thiệu một vòng lặp, một cờ bổ sung, một chồng các ifs lồng nhau , hoặc bất cứ điều gì, nhưng tại sao không xem xét liệu gotocó lẽ là công cụ tốt nhất cho công việc? Nói cách khác, mọi người chuẩn bị chịu đựng sự xấu xí đến mức nào để tránh sử dụng một tính năng ngôn ngữ tích hợp cho mục đích dự định của nó? Ý kiến ​​của tôi là ngay cả việc thêm một lá cờ cũng là một cái giá quá cao. Tôi thích các biến của mình đại diện cho những thứ trong miền vấn đề hoặc giải pháp. 'Chỉ để tránh một goto' không cắt bỏ nó.

Tôi sẽ chấp nhận câu trả lời đầu tiên đưa ra mẫu C để phân nhánh cho một khối dọn dẹp. IMO, điều này là trường hợp mạnh nhất cho một gototrong số tất cả các câu trả lời đã đăng, chắc chắn nếu bạn đo lường nó bằng những thách thức mà người ghét phải trải qua để tránh nó.


11
Tôi không hiểu tại sao các gotophobes không chỉ yêu cầu "#define goto report_to_your_supervisor_for_re_education_through_labour" ở đầu tệp bao gồm của dự án. Nếu nó luôn sai, hãy biến nó thành không thể. Nếu không, đó là đôi khi ngay ...
Steve Jessop

14
"không thể được sử dụng trong mã thực"? Tôi sử dụng nó trong mã "thực" bất cứ lúc nào nó là công cụ tốt nhất cho công việc. "Thành ngữ được thiết lập" là một cách nói hay cho "chủ nghĩa giáo điều mù quáng".
Dan Molding

7
Tôi đồng ý rằng "goto" có thể hữu ích (có những ví dụ tuyệt vời bên dưới), nhưng tôi không đồng ý với ví dụ cụ thể của bạn. Một dòng có nội dung "gotofinity_loop" nghe có vẻ như nó có nghĩa là "chuyển đến phần mã nơi chúng ta sẽ bắt đầu lặp lại mãi mãi", như trong "initialize (); set_things_up (); gotofinity_loop;" khi điều bạn thực sự muốn truyền đạt là "bắt đầu lần lặp tiếp theo của vòng lặp mà chúng ta đã có", điều này hoàn toàn khác. Nếu bạn đang cố lặp lại và ngôn ngữ của bạn có các cấu trúc được thiết kế đặc biệt để lặp lại, hãy sử dụng chúng để rõ ràng hơn. while (true) {foo ()} khá rõ ràng.
Josh

6
Một nhược điểm lớn đối với ví dụ của bạn là không rõ ohter nào đặt trong mã có thể quyết định chuyển đến nhãn này. Vòng lặp vô hạn "bình thường" ( for (;;)) không có điểm đầu vào đáng ngạc nhiên.
jalf

3
@ György: có, nhưng đó không phải là điểm vào.
jalf

Câu trả lời:


87

Đây là một mẹo mà tôi đã nghe về những người sử dụng. Tôi chưa bao giờ nhìn thấy nó trong tự nhiên. Và nó chỉ áp dụng cho C vì C ++ có RAII để làm điều này một cách dễ hiểu hơn.

void foo()
{
    if (!doA())
        goto exit;
    if (!doB())
        goto cleanupA;
    if (!doC())
        goto cleanupB;

    /* everything has succeeded */
    return;

cleanupB:
    undoB();
cleanupA:
    undoA();
exit:
    return;
}

2
Có gì sai với điều này? (ngoại trừ thực tế là các bình luận không hiểu dòng mới) void foo () {if (doA ()) {if (doB ()) {if (doC ()) {/ * mọi thứ đã thành công * / return; } hoàn tác (); } hoàn tác (); } trở về; }
Artelius

6
Các khối thừa gây ra sự thụt lề không cần thiết, khó đọc. Nó cũng không hoạt động nếu một trong các điều kiện nằm trong vòng lặp.
Adam Rosenfield 29/10/08

26
Bạn có thể thấy rất nhiều loại mã này trong hầu hết các thứ Unix cấp thấp (chẳng hạn như hạt nhân linux). Trong C, đó là thành ngữ tốt nhất để khôi phục lỗi IMHO.
David Cournapeau 29/10/08

8
Như cournape đề cập, hạt nhân Linux sử dụng phong cách này tất cả các thời gian .
CesarB 29/10/08

8
Không chỉ nhân linux, hãy xem các mẫu trình điều khiển Windows từ microsoft và bạn sẽ tìm thấy mẫu tương tự. Nói chung đây là một cách C để xử lý các trường hợp ngoại lệ và rất hữu ích :). Tôi thường chỉ thích 1 nhãn và trong một vài trường hợp có thể tránh được 2. 3 trong 99% trường hợp.
Ilya

85

Nhu cầu cổ điển cho GOTO trong C như sau

for ...
  for ...
    if(breakout_condition) 
      goto final;

final:

Không có cách nào đơn giản để thoát ra khỏi các vòng lồng nhau mà không có goto.


49
Thông thường khi nhu cầu này xuất hiện, tôi có thể sử dụng trả lại thay thế. Nhưng bạn cần viết các hàm nhỏ để nó hoạt động theo cách đó.
Darius Bacon

7
Tôi chắc chắn đồng ý với Darius - hãy cấu trúc lại nó thành một chức năng và thay vào đó quay lại!
metao

9
@metao: Bjarne Stroustrup không đồng ý. Trong cuốn sách Ngôn ngữ lập trình C ++ của anh ấy, đây chính xác là ví dụ được đưa ra về cách "sử dụng tốt" goto.
paercebal

19
@Adam Rosenfield: Toàn bộ vấn đề với goto, được Dijkstra nhấn mạnh, là lập trình có cấu trúc cung cấp các cấu trúc dễ hiểu hơn. Làm cho mã khó đọc để tránh goto chứng minh rằng tác giả thất bại trong việc hiểu bài luận mà ...
Steve Jessop

5
@Steve Jessop: Không chỉ mọi người hiểu lầm bài luận, hầu hết những người sùng bái "không đi đến" đều không hiểu bối cảnh lịch sử mà nó được viết.
CHỈ LÀ Ý KIẾN chính xác của TÔI

32

Đây là ví dụ không ngớ ngẩn của tôi, (từ Stevens APITUE) cho các cuộc gọi hệ thống Unix có thể bị gián đoạn bởi một tín hiệu.

restart:
    if (system_call() == -1) {
        if (errno == EINTR) goto restart;

        // handle real errors
    }

Thay thế là một vòng lặp suy biến. Phiên bản này đọc giống như tiếng Anh "nếu cuộc gọi hệ thống bị gián đoạn bởi một tín hiệu, hãy khởi động lại nó".


3
cách này được sử dụng cho ví dụ bộ lập lịch linux có một goto như thế này nhưng tôi sẽ nói rằng có rất ít trường hợp mà goto ngược được chấp nhận và nói chung nên tránh.
Ilya

8
@Amarghosh, continuechỉ là gotomột chiếc mặt nạ.
jball

2
@jball ... hmm .. để tranh luận, vâng; bạn có thể tạo mã dễ đọc với mã goto và spaghetti với tiếp tục .. Cuối cùng thì điều đó phụ thuộc vào người viết mã. Vấn đề là nó dễ dàng bị lạc với goto hơn là với tiếp tục. Và những người mới thường sử dụng chiếc búa đầu tiên mà họ nhận được cho mọi vấn đề.
Amarghosh

2
@Amarghosh. Mã 'cải tiến' của bạn thậm chí không tương đương với mã gốc - nó lặp lại mãi mãi trong trường hợp thành công.
fizzer

3
@fizzer oopsie .. nó sẽ cần hai else breaks (một cho mỗi IFS) để làm cho nó tương đương .. những gì tôi có thể nói ... gotohay không, mã của bạn là chỉ tốt như bạn :(
Amarghosh

14

Nếu thiết bị của Duff không cần goto, thì bạn cũng không nên! ;)

void dsend(int count) {
    int n;
    if (!count) return;
    n = (count + 7) / 8;
    switch (count % 8) {
      case 0: do { puts("case 0");
      case 7:      puts("case 7");
      case 6:      puts("case 6");
      case 5:      puts("case 5");
      case 4:      puts("case 4");
      case 3:      puts("case 3");
      case 2:      puts("case 2");
      case 1:      puts("case 1");
                 } while (--n > 0);
    }
}

mã trên từ mục nhập Wikipedia .


2
Xin chào các bạn, nếu bạn sẽ không tán thành, một bình luận ngắn gọn về lý do tại sao sẽ rất tuyệt. :)
Mitch Wheat

10
Đây là một ví dụ của một ngụy biện logic còn được gọi là "khiếu nại đối với thẩm quyền". Kiểm tra nó trên Wikipedia.
Marcus Griep 29/10/08

11
hài hước thường là không được đánh giá ở đây ...
Steven A. Lowe

8
thiết bị của duff có làm bia không?
Steven A. Lowe

6
cái này có thể làm 8 cái cùng một lúc ;-)
Jasper Bekkers. 31/10/08

14

Knuth đã viết một bài báo "Lập trình có cấu trúc với câu lệnh GOTO", bạn có thể lấy ví dụ từ đây . Bạn sẽ tìm thấy nhiều ví dụ ở đó.


Giấy này có vẻ sâu. Tôi sẽ đọc nó mặc dù. Cảm ơn
fizzer

2
Tờ giấy đó đã lỗi thời, thậm chí còn chẳng vui chút nào. Các giả định của Knuth ở đó đơn giản là không còn giữ được nữa.
Konrad Rudolph

3
Những giả định nào? Các ví dụ của anh ấy ngày nay rất thực tế đối với một ngôn ngữ thủ tục như C (anh ấy cung cấp cho chúng bằng một số mã giả) như chúng ở thời điểm đó.
zvrba

8
Tôi thất vọng vì bạn đã không viết :: Bạn có thể GOTO 'ở đây' để lấy nó, cách chơi chữ đối với tôi sẽ là không thể chịu đựng được nếu không thực hiện!
RhysW

12

Rất phổ biến.

do_stuff(thingy) {
    lock(thingy);

    foo;
    if (foo failed) {
        status = -EFOO;
        goto OUT;
    }

    bar;
    if (bar failed) {
        status = -EBAR;
        goto OUT;
    }

    do_stuff_to(thingy);

OUT:
    unlock(thingy);
    return status;
}

Trường hợp duy nhất tôi từng sử dụng gotolà nhảy về phía trước, thường là ra khỏi khối và không bao giờ vào khối. Điều này tránh lạm dụng do{}while(0)và các cấu trúc khác làm tăng việc lồng vào nhau, trong khi vẫn duy trì mã có cấu trúc, có thể đọc được.


5
Tôi nghĩ đây là cách xử lý lỗi chính tả C. Tôi không thể nhìn thấy nó thay thế độc đáo, có thể đọc được tốt hơn bất kỳ cách nào khác Trân
Friedrich

Tại sao không ... do_stuff(thingy) { RAIILockerObject(thingy); ..... /* -->*/ } /* <---*/ :)
Петър Петров

1
@ ПетърПетров Đó là một mô hình trong C ++ mà không có tương tự trong C.
ephemient

Hoặc trong một ngôn ngữ có cấu trúc hơn C ++, try { lock();..code.. } finally { unlock(); }Nhưng vâng, C không có ngôn ngữ tương đương.
Blindy

12

Tôi không có gì chống lại gotos nói chung, nhưng tôi có thể nghĩ ra một số lý do tại sao bạn không muốn sử dụng chúng cho một vòng lặp như bạn đã đề cập:

  • Nó không giới hạn phạm vi do đó bất kỳ biến tạm thời nào bạn sử dụng bên trong sẽ không được giải phóng cho đến sau này.
  • Nó không giới hạn phạm vi do đó nó có thể dẫn đến lỗi.
  • Nó không giới hạn phạm vi do đó bạn không thể sử dụng lại các tên biến tương tự sau này trong mã tương lai trong cùng phạm vi.
  • Nó không giới hạn phạm vi do đó bạn có cơ hội bỏ qua khai báo biến.
  • Mọi người không quen với nó và nó sẽ làm cho mã của bạn khó đọc hơn.
  • Các vòng lặp lồng nhau của loại này có thể dẫn đến mã spaghetti, các vòng lặp thông thường sẽ không dẫn đến mã spaghetti.

1
là inf_loop: {/ * nội dung vòng lặp * /} goto inf_loop; tốt hơn? :)
quinmars

2
Điểm 1-4 là đáng ngờ đối với ví dụ này ngay cả khi không có dấu ngoặc nhọn. 1 Đó là một vòng lặp vô hạn. 2 Quá mơ hồ để giải quyết. 3 Cố gắng ẩn một biến cùng tên trong một phạm vi bao quanh là một cách thực hành kém. 4. Một goto lùi không thể bỏ qua một khai báo.
fizzer

1-4 như với tất cả các vòng lặp vô hạn, bạn thường có một số loại điều kiện ngắt ở giữa. Vì vậy, chúng có thể áp dụng được. Re một goto bakward không thể bỏ qua một tuyên bố ... không phải tất cả gotos là ngược ...
Brian R. Bondy

7

Một điểm tốt để sử dụng goto là trong một quy trình có thể hủy bỏ tại một số điểm, mỗi điểm yêu cầu nhiều mức độ dọn dẹp khác nhau. Gotophobes luôn có thể thay thế gotos bằng mã có cấu trúc và một loạt các bài kiểm tra, nhưng tôi nghĩ điều này đơn giản hơn vì nó loại bỏ thụt lề quá mức:

if (! openDataFile ())
  goto bỏ;

if (! getDataFromFile ())
  goto closeFileAndQuit;

if (! secureSomeResources)
  goto freeResourcesAndQuit;

// Làm thêm ở đây ....

freeResourcesAndQuit:
   // tài nguyên miễn phí
closeFileAndQuit:
   // Đóng tập tin
bỏ:
   // bỏ đi!

Tôi sẽ thay thế này với một tập hợp các chức năng: freeResourcesCloseFileQuit, closeFileQuit, và quit.
RCIX

4
Nếu bạn đã tạo 3 hàm bổ sung này, bạn cần phải chuyển con trỏ / xử lý đến các tài nguyên và tệp để được giải phóng / đóng. Có thể bạn sẽ thực hiện lệnh gọi freeResourcesCloseFileQuit () closeFileQuit (), đến lượt nó sẽ gọi lệnh thoát (). Bây giờ bạn có 4 hàm được kết hợp chặt chẽ để duy trì và 3 trong số chúng có thể sẽ được gọi cùng lúc: từ hàm đơn ở trên. Nếu bạn nhấn mạnh vào việc tránh goto, IMO, các khối if () lồng nhau có ít chi phí hơn và dễ đọc và dễ bảo trì hơn. Bạn thu được gì với 3 chức năng bổ sung?
Adam Liss

7

@ fizzer.myopenid.com: đoạn mã đã đăng của bạn tương đương với đoạn mã sau:

    while (system_call() == -1)
    {
        if (errno != EINTR)
        {
            // handle real errors

            break;
        }
    }

Tôi chắc chắn thích hình thức này hơn.


1
OK, tôi biết lệnh break chỉ là một hình thức chấp nhận được hơn goto ..
Mitch Wheat

10
Đối với mắt tôi, nó khó hiểu. Đó là một vòng lặp mà bạn không mong đợi nhập vào đường dẫn thực thi thông thường, vì vậy logic có vẻ ngược. Vấn đề quan điểm, mặc dù.
fizzer 29/10/08

1
Ngược? Nó bắt đầu, nó tiếp tục, nó rơi xuống. Tôi nghĩ rằng hình thức này rõ ràng hơn nói rõ ý định của nó.
Mitch Wheat

8
Tôi đồng ý với fizzer ở đây rằng goto cung cấp một kỳ vọng rõ ràng hơn về giá trị của điều kiện.
Marcus Griep 29/10/08

4
Đoạn mã này dễ đọc hơn fizzer theo cách nào.
erikkallen

6

Mặc dù tôi ngày càng ghét mô hình này theo thời gian, nhưng nó đã đi sâu vào lập trình COM.

#define IfFailGo(x) {hr = (x); if (FAILED(hr)) goto Error}
...
HRESULT SomeMethod(IFoo* pFoo) {
  HRESULT hr = S_OK;
  IfFailGo( pFoo->PerformAction() );
  IfFailGo( pFoo->SomeOtherAction() );
Error:
  return hr;
}

5

Đây là một ví dụ về goto tốt:

// No Code

2
ờ, không có vấn đề gì? (cố gắng không thành công tại buồn cười: d)
moogs

9
Đây không phải là thực sự hữu ích
Joseph

Tôi nghĩ điều này thật buồn cười. Làm tốt. +1
Fantastic Mr Fox

@FlySwat FYI: Tìm thấy điều này trong hàng đợi đánh giá chất lượng thấp. Cân nhắc chỉnh sửa.
Paul

1

Tôi đã thấy goto được sử dụng đúng cách nhưng các tình huống bình thường rất xấu. Nó chỉ là khi việc sử dụng của gotochính nó kém hơn rất nhiều so với ban đầu. @Johnathon Holland vấn đề là phiên bản của bạn kém rõ ràng hơn. mọi người dường như sợ hãi các biến cục bộ:

void foo()
{
    bool doAsuccess = doA();
    bool doBsuccess = doAsuccess && doB();
    bool doCsuccess = doBsuccess && doC();

    if (!doCsuccess)
    {
        if (doBsuccess)
            undoB();
        if (doAsuccess)
            undoA();
    }
}

Và tôi thích các vòng lặp như thế này nhưng một số người thích hơn while(true).

for (;;)
{
    //code goes here
}

2
Đừng bao giờ so sánh giá trị boolean với true hoặc false. Nó đã là một boolean; chỉ cần sử dụng "doBsuccess = doAsuccess && doB ();" và "if (! doCsuccess) {}" thay vào đó. Nó đơn giản hơn và bảo vệ bạn khỏi những lập trình viên thông minh viết những thứ như "#define true 0" bởi vì, tốt, vì họ có thể. Nó cũng bảo vệ bạn khỏi những lập trình viên trộn lẫn int và bool, sau đó giả sử bất kỳ giá trị nào khác 0 đều đúng.
Adam Liss 23/12/10

Cảm ơn bạn và == trueđã xóa điểm. Dù sao điều này cũng gần với phong cách thực của tôi hơn. :)
Charles Beattie

0

Mối quan tâm của tôi về điều này là bạn mất phạm vi khối; bất kỳ biến cục bộ nào được khai báo giữa các gotos vẫn còn hiệu lực nếu vòng lặp bị phá vỡ. (Có thể bạn đang giả định rằng vòng lặp chạy mãi mãi; tôi không nghĩ đó là điều mà người viết câu hỏi ban đầu đã hỏi.)

Vấn đề về phạm vi là một vấn đề với C ++, vì một số đối tượng có thể phụ thuộc vào dtor của chúng được gọi vào những thời điểm thích hợp.

Đối với tôi, lý do tốt nhất để sử dụng goto là trong quá trình khởi tạo nhiều bước trong đó điều quan trọng là tất cả các inits đều được sao lưu nếu một lỗi không thành công, đó là:

if(!foo_init())
  goto bye;

if(!bar_init())
  goto foo_bye;

if(!xyzzy_init())
  goto bar_bye;

return TRUE;

bar_bye:
 bar_terminate();

foo_bye:
  foo_terminate();

bye:
  return FALSE;

0

Bản thân tôi không sử dụng goto, tuy nhiên tôi đã từng làm việc với một người sẽ sử dụng chúng trong các trường hợp cụ thể. Nếu tôi nhớ không lầm, cơ sở lý luận của anh ấy là xung quanh các vấn đề về hiệu suất - anh ấy cũng có các quy tắc cụ thể về cách thức . Luôn có cùng một hàm và nhãn luôn ở DƯỚI ĐÂY của câu lệnh goto.


4
Dữ liệu bổ sung: lưu ý rằng bạn không thể sử dụng goto để đi ra ngoài chức năng, và rằng trong C ++, không được phép để bỏ qua một đối tượng xây dựng thông qua một goto
paercebal

0
#include <stdio.h>
#include <string.h>

int main()
{
    char name[64];
    char url[80]; /*The final url name with http://www..com*/
    char *pName;
    int x;

    pName = name;

    INPUT:
    printf("\nWrite the name of a web page (Without www, http, .com) ");
    gets(name);

    for(x=0;x<=(strlen(name));x++)
        if(*(pName+0) == '\0' || *(pName+x) == ' ')
        {
            printf("Name blank or with spaces!");
            getch();
            system("cls");
            goto INPUT;
        }

    strcpy(url,"http://www.");
    strcat(url,name);
    strcat(url,".com");

    printf("%s",url);
    return(0);
}

-1

@Greg:

Tại sao không làm ví dụ của bạn như thế này:

void foo()
{
    if (doA())
    {    
        if (doB())
        {
          if (!doC())
          {
             UndoA();
             UndoB();
          }
        }
        else
        {
          UndoA();
        }
    }
    return;
}

13
Nó bổ sung thêm các mức độ thụt lề không cần thiết, có thể trở nên thực sự khó hiểu nếu bạn có một số lượng lớn các chế độ lỗi có thể xảy ra.
Adam Rosenfield 29/10/08

6
Tôi sẽ thụt lề trên goto bất cứ ngày nào.
FlySwat 29/10/08

13
Ngoài ra, nó có nhiều dòng mã hơn, có một lệnh gọi hàm dư thừa trong một trong các trường hợp và khó hơn nhiều để thêm doD vào một cách chính xác.
Patrick

6
Tôi đồng ý với Patrick - Tôi đã thấy thành ngữ này được sử dụng với một số điều kiện lồng vào độ sâu khoảng 8 cấp độ. Rất khó chịu. Và rất dễ bị lỗi, đặc biệt là khi cố gắng thêm một cái gì đó mới vào hỗn hợp.
Michael Burr

11
Mã này chỉ là hét lên "Tôi sẽ có một lỗi trong vài tuần tới" ai đó sẽ quên hoàn tác điều gì đó. Bạn cần hoàn tác tất cả ở cùng một nơi. Nó giống như "cuối cùng" trong các ngôn ngữ OO bản địa.
Ilya
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.