문제

나는 상당히 기본적인 반복 여야하는 것과 함께 일하고 있습니다. 나는 Ruby 코드로 그것을 성취 할 수 있지만 이미 C 확장자로 일하고 있으므로이 기능을 나머지 코드로 유지하는 것이 좋습니다. 특히이 작업 이후로 (한 가지 방법 또는 다른) 문제없이.

문제는 rb_block_call입니다. readme.ext는 RB_BLOCK_CALL을 설명하는 방법이 있습니다.

VALUE rb_block_call(VALUE recv, ID mid, int argc, VALUE * argv,
          VALUE (*func) (ANYARGS), VALUE data2)
.

은 recv에서 메소드를 호출합니다. 기호로 지정된 메서드 이름입니다 중간, 펑크를 블록으로 공급합니다. Func는 수익률로부터 가치를 받게됩니다 첫 번째 인수로서 DATA2 둘째, ARGC / ARGV 셋째 / 네 번째 인수.

그래서, 나의 이해 (루비 내부를보고 확인)는 수신 기능이 다음과 같이 보일 것입니다 :

VALUE function( VALUE rb_yield_value, VALUE data2, int argc, VALUE argv );
.

그리고 여기 우리는 우리의 문제를 해결합니다. 내 유스 케이스 (아래에 포함 할 것인가)에서는 RB_YIELD_VALUE 및 DATA2가 예상대로 전달됩니다. 다른 한편으로는 항상 1, argv [0]은 rb_yield_value, argv [1]이 거짓이고, argv [2]는 rb_yield_value, argv [3]은 예외를 throw합니다.

argc와 argv에 대한 내가 통과하는 것이 중요하지 않습니다. 0 및 null 결과가 qtrue로 설정된 값과 값과 동일합니다. ARGC / ARGV의 모든 것이 설명 된대로 남아 있습니다.

여기에있는 코드가 있습니다 :

VALUE rb_RPBDB_DatabaseObject_internal_cursorForCallingContext( VALUE rb_self ) {

    //  when we are looking for the contextual iterator, we look up the current backtrace
    //  at each level of the backtrace we have an object and a method;
    //  if this object and method match keys present in self (tracking calling contexts for iteration in this iteration class) return cursor

    VALUE   rb_cursor_context_storage_hash  =   rb_RPBDB_DatabaseObject_internal_cursorContextStorageHash( rb_self );

    VALUE   rb_cursor   =   Qnil;

    if ( RHASH_SIZE( rb_cursor_context_storage_hash ) ) {

        rb_block_call(  rb_mKernel, 
                        rb_intern( "each_backtrace_frame" ), 
                        1, 
                        & rb_cursor_context_storage_hash, 
                        rb_RPBDB_DatabaseObject_internal_each_backtrace_frame, 
                        rb_cursor );    
    }

    return rb_cursor;
}

//  walk up the stack one frame at a time
//  for each frame we need to see if object/method are defined in our context storage hash
VALUE rb_RPBDB_DatabaseObject_internal_each_backtrace_frame(    VALUE   rb_this_backtrace_frame_hash, 
                                                                VALUE   rb_cursor_return,
                                                                int     argc,
                                                                VALUE*  args )  {

    //  why are we getting 3 args when argc is 1 and none of the 3 match what was passed?
    VALUE   rb_cursor_context_storage_hash  =   args[ 0 ];

    //  each frame is identifiable as object/method
    VALUE   rb_this_frame_object    =   rb_hash_aref(   rb_this_backtrace_frame_hash,
                                                        ID2SYM( rb_intern( "object" ) ) );
    VALUE   rb_this_frame_method    =   rb_hash_aref(   rb_this_backtrace_frame_hash,
                                                        ID2SYM( rb_intern( "method" ) ) );

    //  we likely have "block in ..." for our method; we only want the "..."
    rb_this_frame_method    =   ID2SYM( rb_to_id( rb_funcall(   rb_obj_as_string( rb_this_frame_method ),
                                                                rb_intern( "gsub" ),
                                                                2,
                                                                rb_str_new2( "block in " ),
                                                                rb_str_new2( "" ) ) ) );

    VALUE   rb_cursor_object_context_hash   =   rb_RPBDB_DatabaseObject_internal_cursorObjectContextStorageHash(    rb_cursor_context_storage_hash,
                                                                                                                    rb_this_frame_object);

    if ( RHASH_SIZE( rb_cursor_object_context_hash ) )  {

        rb_cursor_return    =   rb_hash_aref(   rb_cursor_object_context_hash,
                                                rb_this_frame_method );

    }

    return rb_cursor_return;
}
.

Ruby Internals는 argc / argv와 함께 rb_block_call의 많은 예를 보이지 않습니다 ... 대부분의 1 ~ 2에서 나는 그들 모두가 그들을 사용하는 것이 아니라 내부적으로 값을 릴레이하는 것으로 믿습니다.

생각?

도움이 되었습니까?

해결책

나는 루비 C 확장에 꽤 새로운 것이지만, 당신의 혼란이있는 곳은 생각합니다.

VALUE rb_block_call(VALUE recv, ID mid, int argc, VALUE argv[],
    VALUE (*func) (ANYARGS), VALUE data2)
.

argc / argv는 여기에 전화를 걸어 ruby 함수에 대한 인수입니다.

c-function의 블록으로 불리는 :

VALUE block_function(VALUE rb_yield_value, VALUE data2, int argc, VALUE argv[])
.

argc / argv는 블록의 인수입니다.

간단한 예제가 주입

여기에 c 번역이 있습니다 : [1,2,3]. {| SUM, E |sum + e}

#include "ruby.h"

static VALUE rb_puts(VALUE obj) {
  return rb_funcall(rb_mKernel, rb_intern("puts"), 1, obj);
}

static VALUE inject_block(VALUE yield_value, VALUE data2, int argc, VALUE argv[]) {
  printf("\nyield_value:\n");
  rb_puts(yield_value);
  printf("data2:\n");
  rb_puts(data2);
  printf("argc: %d\n", argc);
  printf("argv:\n");
  int i;
  for(i = 0; i < argc; ++i) {
    printf("argv %d:\n", i);
    rb_puts(argv[i]);
  }

  VALUE sum = argv[0];
  VALUE e = argv[1];// or yield_value
  return INT2FIX(FIX2INT(sum) + FIX2INT(e));
}

static VALUE rb_block_call_test(int argc, VALUE argv[]) {
  VALUE ary = rb_ary_new();
  int i;
  for(i = 0; i < 3; ++i) {
    rb_ary_push(ary, INT2FIX(i+1));
  }
  VALUE block_argv[1];
  block_argv[0] = INT2FIX(0);
  ary = rb_block_call(ary,
                rb_intern("inject"),
                1, // argc
                block_argv, //argv is a C-array of VALUE
                inject_block,
                Qtrue // data2
                );
  return ary;
}

void Init_rb_block_call() {
  rb_define_global_function("rb_block_call_test", rb_block_call_test, 0);
}
.

rb_block_call_test 호출의 출력 :

yield_value: 0 # sum = argv[0]
data2: true
argc: 2
argv:
argv 0: 0 # sum
argv 1: 1 # e

yield_value: 1
data2: true
argc: 2
argv:
argv 0: 1
argv 1: 2

yield_value: 3
data2: true
argc: 2
argv:
argv 0: 3
argv 1: 3

# => 6
.

나는 yivel_value가 항상 argv [0]

이라고 생각한다.

블록과 발신자간에 정보를 전달하려면 DATA2

를 사용하십시오.

예제에서 #each_backtrace_frame이 하나의 "backtrace_frame"을 생성하고 있으므로 블록의 ARGC / ARGV가 항상 1 / the_backtrace_frame 인 이유입니다.나는 #each_backtrace_frame이 당신이 일부를지나려고했을 때 오류가 발생하지 않았기 때문에 어떤 수의 인수를 허용한다고 믿습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top