too*_*oom 5 r class pseudocode
在像java这样的常见编程语言中,每个文件通常对应一个类.
我刚刚开始使用R.我想构建一个小程序,我想创建一个像这样的特定文件和目录结构
Run Code Online (Sandbox Code Playgroud)Main.R # the main control script MyClass.R # A class that is referenced from within Main.R ProcessData.R # Another class that uses an object of MyClass.R as input
所以我想做这样的事情(伪代码):
Main.R
Run Code Online (Sandbox Code Playgroud)myc <- new MyClass # create a new instance of MyClass from within Main.R pd <- new ProcessData pd$processMyClass( myc ) # call a method in ProcessData that processes the myc object in some way
所以这是相当抽象的,但我只想知道这在原则上是否可能在R中.
更新:我需要更具体.因此问题是:如何通过保持以下玩具程序的相同数量的文件和结构将以下java程序转换为R程序?
Main.java:
public static void main( String[] args ) {
MyClass myc = new MyClass("SampleWord");
ProcessData pd = new ProcessData();
pd.processData( myc );
}
Run Code Online (Sandbox Code Playgroud)
MyClass.java
class MyClass {
public String word;
public MyClass( String word ) {
this.word = word;
}
}
Run Code Online (Sandbox Code Playgroud)
ProcessData.java
class ProcessData.java {
public void processData( MyClass myc ) {
System.out.println( "pd.processData = " + myc.word );
}
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*gan 10
查看R,S3,S4和Reference类中的三个类系统.
## S3 methods, Section 5 of
RShowDoc("R-lang")
## S4 classes
?Classes
?Methods
## Reference classes
?ReferenceClasses
Run Code Online (Sandbox Code Playgroud)
使用Java背景时,您会想要使用引用类,但这些引用类具有"引用语义"和远程操作(更改一个对象会更改引用相同数据的另一个对象),而大多数R用户希望"复制更改" '语义学.一个人可以在S3课程上取得很大的进步,但在我看来,采用S4会更加自律.S4的功能会给你带来惊喜,部分原因是类系统比java更接近普通的lisp对象系统.
还有其他意见和选择.
我不确定你的'ProcessData'的设计目标是什么; 我将把你的两个类实现为一个类,一个泛型,以及一个在MyClass类上运行的泛型的方法.
## definition and 'low-level' constructor
.MyClass <- setClass("MyClass", representation(word="character"))
## definition of a generic
setGeneric("processData", function(x, ...) standardGeneric("processData"))
setMethod("processData", "MyClass", function(x, ...) {
cat("processData(MyClass) =", x@word, "\n")
})
Run Code Online (Sandbox Code Playgroud)
这是完整且功能齐全的
> myClass <- .MyClass(word="hello world")
> processData(myClass)
processData(MyClass) = hello world
Run Code Online (Sandbox Code Playgroud)
这三个代码行可能放在两个文件中,"AllGenerics.R"和"MyClass.R"(包括方法)或三个文件"AllGenerics.R","AllClasses.R","processData-methods.R"(请注意,方法与泛型相关,并在类上发送).
通常会添加一个更加用户友好的构造函数,例如,向用户提供有关预期数据类型的提示或执行复杂的参数初始化步骤
MyClass <- function(word=character(), ...)
{
.MyClass(word=word, ...)
}
Run Code Online (Sandbox Code Playgroud)
通常,人们需要插槽接入,而不是直接插槽接入.这可以是一个简单的函数(如图所示)或一般的+方法.
word <- function(x, ...) x@word
Run Code Online (Sandbox Code Playgroud)
如果要更新插槽,则编写替换功能或方法.函数或方法通常有三个参数,即要更新的对象,可能的附加参数以及用于更新对象的值.这是一个通用+方法实现
setGeneric("word<-", function(x, ..., value) standardGeneric("word<-"))
setReplaceMethod("word", c("MyClass", "character"), function(x, ..., value) {
## note double dispatch on x=MyClass, value=character
x@word <- value
x
})
Run Code Online (Sandbox Code Playgroud)
一个有点棘手的替代实现是
setReplaceMethod("word", c("MyClass", "character"), function(x, ..., value) {
initialize(x, word=value)
})
Run Code Online (Sandbox Code Playgroud)
它使用initialize泛型和默认方法作为复制构造函数; 如果同时更新多个插槽,这可能很有效.
由于用户可以看到该类,因此需要使用"show"方法以用户友好的方式显示该类,其中泛型(getGeneric("show"))已经存在
setMethod("show", "MyClass", function(object) {
cat("class:", class(object), "\n")
cat("word:", word(object), "\n")
})
Run Code Online (Sandbox Code Playgroud)
现在我们的用户会话看起来像
> myClass
class: MyClass
word: hello world
> word(myClass)
[1] "hello world"
> word(myClass) <- "goodbye world"
> processData(myClass)
processData(MyClass) = goodbye world
Run Code Online (Sandbox Code Playgroud)
R对矢量有效; S4课程也不例外.因此,设计是类的每个槽表示跨越多行的列,而不是单行的元素.我们期望插槽"字"通常包含长度远大于1的向量,并且用于操作以对矢量的所有元素起作用.因此,人们会考虑到这一点来编写方法,例如,将show方法修改为
setMethod("show", "MyClass", function(object) {
cat("class:", class(object), "\n")
cat("word() length:", length(word(object)), "\n")
})
Run Code Online (Sandbox Code Playgroud)
这是更大的数据对象(使用我的Linux系统上的文件)
> amer <- MyClass(readLines("/usr/share/dict/american-english"))
> brit <- MyClass(readLines("/usr/share/dict/british-english"))
> amer
class: MyClass
word() length: 99171
> brit
class: MyClass
word() length: 99156
> sum(word(amer) %in% word(brit))
[1] 97423
> amer_uc <- amer ## no copy, but marked to be copied if either changed
> word(amer_uc) <- toupper(word(amer_uc)) ## two distinct objects
Run Code Online (Sandbox Code Playgroud)
所有这一切都非常有效.
让我们回顾一下S4类的简单实现,直接插槽访问,没有花哨的构造函数.这是美国字典和副本,转化为大写
.MyClass <- setClass("MyClass", representation(word="character"))
amer <- .MyClass(word=readLines("/usr/share/dict/american-english"))
amer_uc <- amer
amer_uc@word <- toupper(amer_uc@word)
Run Code Online (Sandbox Code Playgroud)
请注意,我们是大写amer_uc但不是amer:
> amer@word[99 + 1:10]
[1] "Adana" "Adar" "Adar's" "Addams" "Adderley"
[6] "Adderley's" "Addie" "Addie's" "Addison" "Adela"
> amer_uc@word[99 + 1:10]
[1] "ADANA" "ADAR" "ADAR'S" "ADDAMS" "ADDERLEY"
[6] "ADDERLEY'S" "ADDIE" "ADDIE'S" "ADDISON" "ADELA"
Run Code Online (Sandbox Code Playgroud)
这正是R用户所期待的 - 我创建了一个单独的对象并对其进行了修改; 原始对象未经修改.这是我的主张; 也许我不知道R用户期望什么.我假设R用户并没有真正关注这是一个引用类的事实,但认为它只是另一个R对象,如integer()vector或a data.frame或者返回值lm().
相比之下,这是引用类的最小实现,以及类似的操作
.MyRefClass <- setRefClass("MyRefClass", fields = list(word="character"))
amer <- .MyRefClass(word=readLines("/usr/share/dict/american-english"))
amer_uc <- amer
amer_uc$word <- toupper(amer_uc$word)
Run Code Online (Sandbox Code Playgroud)
但现在我们已经改变了这两个amer和amer_uc!完全由C或Java程序员预期,但不是R用户.
> amer$word[99 + 1:10]
[1] "ADANA" "ADAR" "ADAR'S" "ADDAMS" "ADDERLEY"
[6] "ADDERLEY'S" "ADDIE" "ADDIE'S" "ADDISON" "ADELA"
> amer_uc$word[99 + 1:10]
[1] "ADANA" "ADAR" "ADAR'S" "ADDAMS" "ADDERLEY"
[6] "ADDERLEY'S" "ADDIE" "ADDIE'S" "ADDISON" "ADELA"
Run Code Online (Sandbox Code Playgroud)
引用类下面我们尝试尽可能接近地使用R in复制问题中的java代码.在这三个内置的R类系统(S3,S4,Reference Classes)中,参考类似乎最接近那种风格.Reference Classes是要添加到R的最新类系统,它的快速推广可能是由于熟悉该风格的Java程序员来到R.
(如果你创建了一个包,那么省略所有的源语句.)
Main.R文件:
source("MyClass.R")
source("ProcessData.R")
main <- function() {
myc <- new("MyClass", word = "SampleWord")
pd <- new("ProcessData")
cat("pd$processData =", pd$processData(myc), "\n")
}
Run Code Online (Sandbox Code Playgroud)
MyClass.R文件:
setRefClass("MyClass",
fields = list(word = "character")
)
Run Code Online (Sandbox Code Playgroud)
ProcessData.R文件:
setRefClass("ProcessData",
fields = list(myc = "MyClass"),
methods = list(
processData = function(myc) myc$word
)
)
Run Code Online (Sandbox Code Playgroud)
跑步:
source("Main.R")
main()
Run Code Online (Sandbox Code Playgroud)
原包 的原包实现了起源于自编程语言和存在在一定程度上在JavaScript,Lua和特别的基础面向对象的编程的原型模型IO语言.proto可以很容易地模仿这种风格(正如proto vignette的Traits部分所讨论的那样):
Main.R文件:
source("MyClass.R")
source("ProcessData.R")
library(proto)
main <- function() {
myc <- MyClass$new("SampleWord")
pd <- ProcessData$new()
cat("pd$processData =", pd$processData(myc), "\n")
}
Run Code Online (Sandbox Code Playgroud)
MyClass.R文件:
MyClass <- proto(
new = function(., word) proto(word = word)
)
Run Code Online (Sandbox Code Playgroud)
ProcessData.R文件:
ProcessData <- proto(
new = function(.) proto(.),
processData = function(., myc) myc$word
)
Run Code Online (Sandbox Code Playgroud)
跑步:
source("Main.R")
main()
Run Code Online (Sandbox Code Playgroud)
更新:添加了原型示例.
更新2:改进main并MyClass在参考类示例中.