是否可以在R引用类中包含私有成员字段。玩我的一些在线示例:
> Account <- setRefClass( "ref_Account"
> , fields = list(
> number = "character"
> , balance ="numeric")
> , methods = list(
> deposit <- function(amount) {
> if(amount < 0) {
> stop("deposits must be positive")
> }
> balance <<- balance + amount
> }
> , withdraw <- function(amount) {
> if(amount < 0) {
> stop("withdrawls must be positive")
> }
> balance <<- balance - amount
> }
> ) )
>
>
> tb <- Account$new(balance=50.75, number="baml-029873") tb$balance
> tb$balance <- 12
> tb$balance
我讨厌我可以直接更新余额的事实。也许那个旧的纯粹的OO在我身上,我真的希望能够保持平衡的私密性,至少从课堂外不可设定。
思想
答案 0 :(得分:3)
此答案不适用于R&gt; 3.00,所以不要使用它!
如前所述,您不能拥有私人会员字段。但是,如果使用initialize方法,则余额不会显示为字段。例如,
Account = setRefClass("ref_Account",
fields = list(number = "character"),
methods = list(
initialize = function(balance, number) {
.self$number = number
.self$balance = balance
})
和以前一样,我们将创建一个实例:
tb <- Account$new(balance=50.75, number="baml-0029873")
##No balance
tb
Reference class object of class "ref_Account"
Field "number":
[1] "baml-0029873"
正如我所提到的,它不是真正私密的,因为你仍然可以这样做:
R> tb$balance
[1] 50.75
R> tb$balance = 12
R> tb$balance
[1] 12
答案 1 :(得分:2)
R不是那种语言。没有私人或公共的概念。
答案 2 :(得分:2)
为了解决隐私问题,我创建了一个自己的类,#34; Private&#34;,它有新的方法来访问对象,即$
和[[
。如果客户端尝试访问“私人”,这些方法将引发错误。会员。私人成员由名称(领先期)标识。由于参考对象是R中的环境,因此可以解决此问题,但这是我的解决方案,我认为使用类提供的get / set方法更方便。因此,这更像是来自外部的难以设定的&#39;问题的解决方案。
我已经在R-package中组织了这个,所以下面的代码使用了该包并修改了上面的例子,这样对tb$.balance
的赋值就会产生错误。我还使用函数Class
,它只是setRefClass
的包装器,所以这仍然在方法包提供的R&#39引用类的范围内,并在问题中使用。
devtools::install_github("wahani/aoos")
library("aoos")
Account <- defineRefClass({
Class <- "Account"
contains <- "Private"
number <- "character"
.balance <- "numeric"
deposit <- function(amount) {
if(amount < 0) stop("deposits must be positive")
.balance <<- .balance + amount
}
withdraw <- function(amount) {
if(amount < 0) stop("withdrawls must be positive")
.balance <<- .balance - amount
}
})
tb <- Account(.balance = 50.75, number = "baml-029873")
tb$.balance # error
tb$.balance <- 12 # error
答案 3 :(得分:0)
我遇到了类似的问题,并使用Base R来实现。我倾向于不使用R6之类的第三方程序包使事情变得更难。为了解决这个问题,我访问了定义对象方法的环境,并以此方式存储变量。
在此示例中,我正在尝试实现类似于scikit Learn中的MinMaxScaler:
## Base reference class
setRefClass(
"Transformer",
contains = "VIRTUAL",
methods = list(
fit = function(data) stop("Must implement"),
transform = function(data) stop("Must implement"),
fit_transform = function(data) {
fit(data)
transform(data)
}
))
Transformer API的具体实现。在fit
方法中,我访问定义了fit
的环境。然后,我使用该环境存储中间计算所需的任何变量,并就地更新对象-就像sklearn一样。
MinMaxScaler <-setRefClass(
"MinMaxScaler",
contains = "Transformer",
fields = c(feature_range = "numeric"),
methods = list(
fit = function(data) {
env <- environment(fun = .self$fit)
rng <- range(data, na.rm=TRUE)
env$data_range_ <- diff(range(data, na.rm=TRUE))
env$data_min_ <- rng[[1]]
env$data_max_ <- rng[[2]]
},
transform = function(data) {
env <- environment(fun = .self$transform)
scalef <- diff(range(feature_range))
scalef * (data - env$data_min_) / env$data_range_ + min(feature_range)
}
)
)
为演示此模式,我将创建两个缩放器并分别安装它们:
> ## Dummy data
> set.seed(123)
> z <- rnorm(1e4)
> summary(z)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-3.845320 -0.667969 -0.011089 -0.002372 0.673347 3.847768
>
> scaler1 <- MinMaxScaler(feature_range=c(0, 50))
> summary(scaler1$fit_transform(z))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.00 20.65 24.92 24.98 29.37 50.00
>
> scaler2 <- MinMaxScaler(feature_range=c(-100, 100))
> summary(scaler2$fit_transform(z))
Min. 1st Qu. Median Mean 3rd Qu. Max.
-100.00000 -17.39725 -0.32011 -0.09347 17.47344 100.00000
>
> ## to show the scalers are distinct and not sharing private vars
> summary(scaler1$transform(z))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.00 20.65 24.92 24.98 29.37 50.00
> summary(scaler2$transform(z))
Min. 1st Qu. Median Mean 3rd Qu. Max.
-100.00000 -17.39725 -0.32011 -0.09347 17.47344 100.00000