2010-03-20 25 views

Trả lời

14

Đó là một câu hỏi khá rộng. Về cơ bản, đóng cửa là một con trỏ chỉ dẫn cùng với một số ngữ cảnh được lưu trữ cần thiết để thực hiện các hướng dẫn đúng cách. Bạn chắc chắn có thể ném một cái gì đó như thế này với nhau trong C bằng cách sử dụng cấu trúc và con trỏ chức năng.

Hãy nói rằng bạn thể hiện một đóng cửa mà phải mất hai ints và trả về void như một cấu trúc:

typedef struct VoidClosureIntInt { 
    void (*fn)(int, int); 
    int first; 
    int second; 
} VoidClosureIntInt; 

và giả sử bạn có một hàm:

void Foo(int x, int y); 

Bây giờ, để tạo ra một kết thúc mà sẽ gọi Foo (23, 42), bạn sẽ làm:

VoidClosureIntInt closure = {&Foo, 23, 42}; 

Và sau đó để thực hiện việc đóng, bạn sẽ làm:

(*closure.fn)(closure.first, closure.second); 

Một nếp nhăn khác: hầu hết thời gian khi bạn sử dụng bao đóng, bạn muốn vượt qua ngữ cảnh trong suốt thời gian bạn chặn đóng. (Ví dụ: bạn đang chuyển kết nối vào một hàm thực hiện một số I/O không đồng bộ và cuối cùng sẽ gọi đóng của bạn khi I/O kết thúc). Trong những trường hợp như vậy, bạn phải chắc chắn phân bổ đóng cửa của bạn trên heap, và để xóa đóng cửa của bạn khi bạn đã hoàn thành nó. (Xem ví dụ hoàn chỉnh ở dưới cùng).

Một lưu ý cuối cùng: rõ ràng là có rất nhiều máy móc ở đây, và nó chỉ dành cho một loại đóng (một hàm lấy hai số nguyên args và trả về void). Khi tôi đã nhìn thấy điều này được thực hiện trong C nó thường được thực hiện bởi một máy phát điện mã tạo ra máy móc cho nhiều loại đóng cửa khác nhau. Bạn cũng có thể giảm số lượng boilerplate bằng cách chỉ hỗ trợ các bao đóng có một số (đối số cố định) void * đối số, và sau đó typecasting trong các hàm bạn đang sử dụng để thực hiện các bao đóng đó.

Nếu bạn đang ở trong C++, bạn có thể tận dụng lợi thế của các tính năng ngôn ngữ để thực hiện điều này nhiều hơn một cách chung chung và ít bị đánh máy hơn nhiều. Xem Boost.Function để biết ví dụ.

Full dụ:

#include <stdio.h> 
#include <stdlib.h> 

// Closure support. 

typedef struct VoidClosureIntInt { 
    void (*fn)(int, int); 
    int first; 
    int second; 
} VoidClosureIntInt; 

// The returned closure should be run via RunAndDeleteClosure(). 
VoidClosureIntInt* NewClosure(void (*fn)(int, int), int first, int second) { 
    VoidClosureIntInt* closure = malloc(sizeof(*closure)); 
    closure->fn = fn; 
    closure->first = first; 
    closure->second = second; 
    return closure; 
} 

void RunAndDeleteClosure(VoidClosureIntInt* closure) { 
    (*closure->fn)(closure->first, closure->second); 
    free(closure); 
} 


// Example use. 

void Foo(int x, int y) { 
    printf("x=%d\ny=%d\n", x, y); 
} 

// We take memory ownership of closure. 
void SomeAsynchronousFunction(VoidClosureIntInt* closure) { 
    RunAndDeleteClosure(closure); 
} 

int main(int argc, char** argv) { 
    VoidClosureIntInt* closure = NewClosure(&Foo, 23, 42); 
    SomeAsynchronousFunction(closure); 
    return 0; 
} 
-1

câu trả lời đơn giản:

NO

Xin lỗi, trừ khi bạn thu hẹp này xuống một số loại nhóm rất nhỏ các chức năng của đóng cửa, đó là cách nó được.

+0

Tôi luôn luôn nghĩ đến việc đóng cửa là một khái niệm nguyên tử; làm thế nào bạn sẽ subset nó? – Pierreten

+0

Will Robinson dường như có một ví dụ rất hay về điều này, vì vậy câu trả lời này là không chính xác. –

+0

Will Robinson đang hiển thị một tấn mã để thực hiện 'một tập hợp con nhỏ' (và không hữu ích khủng khiếp) của bao đóng '. – bmargulies

-1

Tôi đoán nó phụ thuộc vào ý tưởng của bạn "đơn giản" là gì.

Có một số triển khai của Đề án được thiết kế để được tích hợp dưới dạng ngôn ngữ mở rộng cho các chương trình C. Liên kết trong một Đề án, viết đóng của bạn trong Đề án, và bạn đã hoàn tất.

Các vấn đề liên quan