Closed wks closed 8 years ago
原因是:用户提供的回调函数除了调用者提供的参数(如spider本身,以及url等),往往还有用户自己的上下文。比如,如果一个用户打算把所有的url写进一个文件,那么他会遇到麻烦:
void p(cspider_t *spider, char*url) { // 这个p函数如何得到main函数里创建的fp呢? } int main() { cspider_t *spider1 = init_cspider(); cspider_t *spider2 = init_cspider(); FILE *fp1 = open("my_url_list1.txt", "w"); FILE *fp2 = open("my_url_list2.txt", "w"); cs_setopt_process(spider1, p); // 如何告诉spider1往fp1里写, cs_setopt_process(spider2, p); // 而spider2往fp2里写呢? }
建议所有的回调函数都多取一个void* user_data参数,这个参数的值在设定回调函数的时候指定。比如:
void* user_data
// 需要修改一下API // 方便起见,单独定义callback的函数签名 typedef void (*ProcessFuncPtr)(cspider_t* spider, char* url, void* user_data); // cs_setopt_process会在回调callback的时候把这里提供的user_data作为第三个函数传给callback void cs_setopt_process(cspider_t *, ProcessFuncPtr callback, void* user_data); // 下面是使用 struct my_context { FILE *fp; }; void p(cspider_t *spider, char*url, void *user_data) { struct my_context *ctx = (struct my_context*)user_data; // 转换一下类型 fprintf(ctx->fp, "URL: %s\n", url); } int main() { cspider_t *spider1 = init_cspider(); cspider_t *spider2 = init_cspider(); FILE *fp1 = open("my_url_list1.txt", "w"); FILE *fp2 = open("my_url_list2.txt", "w"); struct my_context ctx1 = { .fp = fp1 }; struct my_context ctx2 = { .fp = fp2 }; cs_setopt_process(spider1, p, &ctx1); // 都调用p,但让spider1传&ctx1作为第三个参数, cs_setopt_process(spider2, p, &ctx2); // 而spider2传&ctx2作为第三个参数。 fclose(fp1); fclose(fp2); }
非常非常感谢,确实没有考虑到这点。今晚有空就完善这个问题。再次感谢您的指点。
已完善,再次感谢。
原因是:用户提供的回调函数除了调用者提供的参数(如spider本身,以及url等),往往还有用户自己的上下文。比如,如果一个用户打算把所有的url写进一个文件,那么他会遇到麻烦:
建议所有的回调函数都多取一个
void* user_data
参数,这个参数的值在设定回调函数的时候指定。比如: