Se poate trece prin referință cu „R” ?de exemplu, în următorul cod:
setClass("MyClass",
representation(
name="character"
))
instance1 <-new("MyClass",name="Hello1")
instance2 <-new("MyClass",name="Hello2")
array = c(instance1,instance2)
instance1
array
[email protected]="World!"
instance1
array
rezultatul este
> instance1
An object of class “MyClass”
Slot "name":
[1] "World!"
> array
[[1]]
An object of class “MyClass”
Slot "name":
[1] "Hello1"
[[2]]
An object of class “MyClass”
Slot "name":
[1] "Hello2"
dar mi-aș dori să fie
> instance1
An object of class “MyClass”
Slot "name":
[1] "World!"
> array
[[1]]
An object of class “MyClass”
Slot "name":
[1] "World!"
[[2]]
An object of class “MyClass”
Slot "name":
[1] "Hello2"
este posibil?
- Chiar mă întreb de ce au venit cu o implementare atât de neobișnuită. – > Por anilbey.
- Obiecte sau primitive? S3, S4 sau R6? Folosind medii sau altfel? R 1.x, 2.x sau 3.x? Răspunsurile de aici se întind din 2010-15 și nu sunt în dezacord unul cu celălalt. Această întrebare este un dezastru și trebuie curățată. De asemenea, este util ca atunci când se răspunde „Da/Nu” să se citeze versiuni sau date: de exemplu, „începând cu R 3.0 / 2013”. Pentru ca răspunsul să fie pregătit pentru viitor. – > Por smci.
Nu.
Obiectele din instrucțiunile de atribuire sunt imuabile. R va copia obiectul nu doar referința.
> v = matrix(1:12, nrow=4)
> v
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> v1 = v
> v1[,1] # fetch the first column
[1] 1 2 3 4
(rezervă: afirmația de mai sus este adevărată pentru R primitive(de exemplu, vectori, matrici), dar și pentru funcții; nu pot spune cu certitudine dacă este adevărată și pentru toate obiectele R – doar pentru cele mai multe dintre ele, precum și pentru marea majoritate a celor mai des folosite).
Dacă nu vă place acest comportament, puteți renunța la el cu ajutorul unui pachet R. De exemplu, există un pachet R numit R.oo care vă permite să imitați comportamentul pass-by-reference; R.oo este disponibil pe CRAN.
- A se vedea și
mutatr
șiproto
pachete. – > . mutatr
pare a fi nesusținut și nedocumentat. – > .- @doug poți să treci prin referință folosind un
.Call
wrapper al unui C++? – > . - Găsesc acest „Nu” mai degrabă, bine, bold, din moment ce multe pachete par să permită trecerea prin referință, precum și
Rcpp
interfața cu C/C++. – > .
Rețineți că, dacă sperați să folosiți trecerea prin referință doar pentru a evita implicațiile de performanță ale copierii unui obiect care nu este modificat (așa cum se întâmplă frecvent în alte limbaje cu referințe constante), R face acest lucru în mod automat:
n <- 10^7
bigdf <- data.frame( x=runif(n), y=rnorm(n), z=rt(n,5) )
myfunc <- function(dat) invisible(with( dat, x^2+mean(y)+sqrt(exp(z)) ))
myfunc2 <- function(dat) {
x <- with( dat, x^2+mean(y)+sqrt(exp(z)) )
invisible(x)
}
myfunc3 <- function(dat) {
dat[1,1] <- 0
invisible( with( dat, x^2+mean(y)+sqrt(exp(z)) ) )
}
tracemem(bigdf)
> myfunc(bigdf)
> # nothing copied
> myfunc2(bigdf)
> # nothing copied!
> myfunc3(bigdf)
tracemem[0x6e430228 -> 0x6b75fca0]: myfunc3
tracemem[0x6b75fca0 -> 0x6e4306f0]: [<-.data.frame [<- myfunc3
tracemem[0x6e4306f0 -> 0x6e4304f8]: [<-.data.frame [<- myfunc3
>
> library(microbenchmark)
> microbenchmark(myfunc(bigdf), myfunc2(bigdf), myfunc3(bigdf), times=5)
Unit: milliseconds
expr min lq median uq max
1 myfunc2(bigdf) 617.8176 641.7673 644.3764 683.6099 698.1078
2 myfunc3(bigdf) 1052.1128 1134.0822 1196.2832 1202.5492 1206.5925
3 myfunc(bigdf) 598.9407 622.9457 627.9598 642.2727 654.8786
- Foarte util de știut! Aș adăuga, de asemenea, că acest lucru pare să se aplice NUMAI la data.frames. Matricile/Array-urile sunt întotdeauna pass-by-value, după cum tocmai am aflat după câteva ore de scărpinat în ieșirea Rprof. – > .
- rulează din nou acest lucru pe laptopul meu acum: toate timpii sunt aceiași acum (și jumătate din cei de acum cinci ani) – – > .
- Partea de tracemem trebuie să fie explicată un pic – > .
- @AndrewChristianson IIUC, acesta este comportamentul actual, de asemenea pentru
matrix
,array
șitibble
. S-a schimbat comportamentul de când ai postat comentariul tău sau mă înșel? – > . - @OrenMilman oh, Doamne, probabil? acest comentariu este de acum câțiva ani și probabil că a fost făcut cu referire la R 2.15 / 2.14, pe care îl foloseam la acea vreme. – > .
După cum au subliniat mai mulți înainte, acest lucru se poate face prin utilizarea obiectelor din clasa environment
. Există o abordare formală care se bazează pe utilizarea clasei environment
s. Se numește Clase de referință și vă ușurează foarte mult lucrurile. Consultați ?setRefClass
pentru pagina de ajutor pentru intrarea principală. Aceasta descrie, de asemenea, cum se utilizează metodele formale cu clasele de referință.
Exemplu
setRefClass("MyClass",
fields=list(
name="character"
)
)
instance1 <- new("MyClass",name="Hello1")
instance2 <- new("MyClass",name="Hello2")
array = c(instance1,instance2)
instance1$name <- "World!"
Ieșire
> instance1
Reference class object of class "MyClass"
Field "name":
[1] "World!"
> array
[[1]]
Reference class object of class "MyClass"
Field "name":
[1] "World!"
[[2]]
Reference class object of class "MyClass"
Field "name":
[1] "Hello2"
Pass-by-reference este posibil pentru environment
s. Pentru a le utiliza, practic, ori de câte ori creați un obiect, va trebui să creați și un slot de mediu. Dar cred că acest lucru este greoi. Aruncați o privire la Pass by reference pentru S4. și Pointeri și trecerea prin referință în R
- Linkurile funcționează acum. În aceste zile ar trebui să apară S4 înaintea lui S3. – > .
R are acum o bibliotecă care vă permite să faceți OOP folosind referințe. A se vedea ReferenceClasses care face parte din pachetul de metode.
În realitate, aplicația R.oo emulează comportamentul pass-by-reference prin utilizarea mediilor.
Așa cum au afirmat și alții, nu este posibil pentru clasele S4. Dar R oferă acum această posibilitate cu R6 numită referință clase de referință. A se vedea documentația oficială
- R6 este un pachet la care au contribuit utilizatorii. Clasele de referință sunt ceva ce vine cu R (sau mai degrabă cu pachetul de metode al acestuia). R6 este similar cu clasele de referință, după cum se spune în documentație: „Clasele R6 sunt similare cu clasele de referință standard ale R”. – > .
În plus față de celelalte răspunsuri de aici care de fapt trec obiectul prin referință (environment
obiecte și clase de referință), dacă sunteți pur și simplu interesat de apelarea prin referință pentru comoditate sintactică (adică nu vă deranjează datele copiate în interior), ați putea emula acest lucru prin atribuirea valorii finale înapoi la variabila exterioară în timp ce vă întoarceți:
byRef <- function(..., envir=parent.frame(), inherits=TRUE) {
cl <- match.call(expand.dots = TRUE)
cl[c(1, match(c("envir", "inherits"), names(cl), 0L))] <- NULL
for (x in as.list(cl)) {
s <- substitute(x)
sx <- do.call(substitute, list(s), envir=envir)
dx <- deparse(sx)
expr <- substitute(assign(dx, s, envir=parent.frame(), inherits=inherits))
do.call(on.exit, list(expr, add=TRUE), envir=envir)
}
}
Apoi, putem declara argumente de „apel prin referință”:
f <- function(z1, z2, z3) {
byRef(z1, z3)
z1 <- z1 + 1
z2 <- z2 + 2
z3 <- z3 + 3
c(z1, z2, z3)
}
x1 <- 10
x2 <- 20
x3 <- 30
# Values inside:
print(f(x1, x2, x3))
# [1] 11 22 33
# Values outside:
print(c(x1, x2, x3))
# [1] 11 20 33
Rețineți că, dacă accesați variabilele „prin referință” prin numele lor din exterior (x1
, x3
) oriunde în interiorul funcției, veți obține valorile lor încă nemodificate din exterior. De asemenea, această implementare gestionează doar nume simple de variabile ca argumente, astfel încât argumentele indexate, cum ar fi f(x[1], ...)
nu va funcționa (deși ați putea probabil să implementați acest lucru cu o manipulare a expresiilor puțin mai complicată pentru a evita limitarea assign
).
În plus față de celelalte sugestii, puteți scrie, de asemenea, funcții C/C++ care își iau argumentele prin referință și care lucrează pe locși să le apelați direct în R datorită funcției Rcpp
(printre altele).Vedeți în special acest răspuns.