2012-06-09 44 views

Respuesta

33

Descubre la genérica para que sepamos lo que estamos apuntando

> getGeneric("[") 
standardGeneric for "[" defined from package "base" 

function (x, i, j, ..., drop = TRUE) 
standardGeneric("[", .Primitive("[")) 
<bytecode: 0x32e25c8> 
<environment: 0x32d7a50> 
Methods may be defined for arguments: x, i, j, drop 
Use showMethods("[") for currently available ones. 

definir una clase simple

setClass("A", representation=representation(slt="numeric")) 

y poner en práctica un método

setMethod("[", c("A", "integer", "missing", "ANY"), 
    ## we won't support subsetting on j; dispatching on 'drop' doesn't 
    ## make sense (to me), so in rebellion we'll quietly ignore it. 
    function(x, i, j, ..., drop=TRUE) 
{ 
    ## less clever: update slot, return instance 
    ## [email protected] = [email protected][i] 
    ## x 
    ## clever: by default initialize is a copy constructor, too 
    initialize(x, [email protected][i]) 
}) 

en acción:

> a = new("A", slt=1:5) 
> a[3:1] 
An object of class "A" 
Slot "slt": 
[1] 3 2 1 

Existen diferentes estrategias para admitir (implícitamente) muchas firmas, por ejemplo, es probable que también desee admitir valores lógicos y de índice de caracteres, posiblemente para i y j. El más simple es un patrón de "fachada" donde cada método realiza una coerción preliminar a un tipo común de índice de subconjunto, por ejemplo, integer para permitir el reordenamiento y la repetición de entradas de índice, y luego usa callGeneric para invocar un único método eso hace el trabajo de subconjunto de la clase.

No hay diferencias conceptuales para [[, aparte de querer respetar la semántica de devolver el contenido en lugar de otra instancia del objeto como implica el [. Para $ tenemos

> getGeneric("$") 
standardGeneric for "$" defined from package "base" 

function (x, name) 
standardGeneric("$", .Primitive("$")) 
<bytecode: 0x31fce40> 
<environment: 0x31f12b8> 
Methods may be defined for arguments: x 
Use showMethods("$") for currently available ones. 

y

setMethod("$", "A", 
    function(x, name) 
{ 
    ## 'name' is a character(1) 
    slot(x, name) 
}) 

con

> a$slt 
[1] 1 2 3 4 5 
+7

Gracias Martin! Esto es realmente útil (hasta el punto en que estoy violando la regla de "no me dejen los gracias gracias porque es ruido" :-) –

7

lo haría como @Martin_Morgan sugerido para los operadores que usted ha mencionado. Sin embargo, agregaría un par de puntos:

1) Sería cuidadoso al definir un operador $ para acceder a una ranura S4 (a menos que intente acceder a una columna desde un marco de datos que está almacenado en una ranura específica?) . La sugerencia general es escribir funciones de acceso como getMySlot() y setMySlot() para obtener la información que necesita. Puede usar el operador @ para acceder a los datos de esas máquinas tragamonedas, aunque obtener y establecer son las mejores como una interfaz de usuario. Usar $ podría ser confuso para el usuario, que probablemente esperaría un data.frame. Consulte this S4 tutorial de Christophe Genolini para una discusión en profundidad de estos temas. Si esta no es la intención de usar $, haga caso omiso de mi sugerencia (¡pero el tutorial sigue siendo un gran recurso!).

2) Si está definiendo [ y [[ a heredar de otra clase, como vector, también tendrá que definir el() (equivalente a [][[1L]], o el primer elemento de un subconjunto []) y length(). Actualmente estoy escribiendo una clase para heredar de forma numérica, y los métodos numéricos intentarán usar estas funciones de su clase automáticamente. Si la clase es para un uso personal o más limitado, esto puede no ser un problema.

Disculpe, lo hubiera dejado como un comentario, pero soy nuevo en SO y todavía no tengo el representante.

Cuestiones relacionadas