R語言的類有S3類和S4類,S3類用的比較廣,建立簡單粗糙可是靈活,而S4類比較精細,具備跟C++同樣嚴格的結構。這裏咱們主要講S3類。app
S3類內部是一個list,append某個list類名稱,就能成爲該類。list裏面的內容就是咱們所說的屬性.
首先建立一個list函數
me <- list(seq = "ATGC", length = nchar("ATGC")) me $seq [1] "ATGC" $length [1] 4
如今me這個list只屬於list類this
me $seq [1] "ATGC" $length [1] 4 attr(,"class") [1] "list" "DNAseq"
而後咱們append 一個類名"DNAseq",就這樣咱們建立了一個DNAseq類,類的屬性有seq和length,值爲ATGC和4指針
class(me) <- append(class(me), "DNAseq") class(me) [1] "list" "DNAseq"
咱們能夠經過普通的list的方法來得到類的屬性,好比code
me$seq [1] "ATGC" me$length [1] 4
依據剛纔的類的結構,咱們用函數進行類的構建,函數的輸入是要傳入進行類的初始化的值,而函數的返回就是新生成的類。這樣咱們就能夠根據不一樣的初始化值進行類的實例化。
首先構造一個類orm
# Straight forward approach DNAseq <- function(seq = "ATGCATGCATGCATGCATGC"){ me <- list( seq = seq, length = nchar(seq) ) # Set the name for the class class(me) <- append(class(me), "DNAseq") return(me) }
類的實例對象
seq1 <- DNAseq() seq1 $seq [1] "ATGCATGCATGCATGCATGC" $length [1] 20 attr(,"class") [1] "list" "DNAseq"
固然本質仍是list,可是巧妙的利用了函數運行時的局部環境。函數運行時,內部的環境是和外界隔離的,在函數內建立的變量不會影響函數外。而這種方法巧妙的取出了這個內部環境的指針,而且將它放到了list裏面。最後append類名。在環境裏面存放了list的指針,而在list裏面又存放了環境的指針。之因此內部環境沒有消失,我猜測是由於返回的類裏面具備環境的指針的引用,因此內存沒有釋放,是一個智能指針,固然,我沒有對這深究。此次屬性並非直接存放在list裏面,而是存放在函數裏面的環境中。而list裏面放着:方法和當前環境的指針。assign是對環境中某個變量賦值,能夠用get函數中得到環境中變量的值。繼承
# Local enviroment approach DNASeq <- function(seq = "ATGCATGCATGCATGCATGC"){ ## Get the enviroment for this thisEnv <- environment() seq <- seq length <- nchar(seq) ## Create the list used to represent the ## object for this class me <- list( ## Define the enviroment where this list is defined so ## that I can refer to it thisEnv = thisEnv, ## Method to refer to the current enviroment getEnv = function(){ return(get("thisEnv", thisEnv)) } ) ## Define the value of list within the ## current enviroment assign("this", me, envir = thisEnv) ##Set the name for the class class(me) <- append(class(me), "DNASeq") return(me) }
實例化內存
seq2 <- DNASeq() seq2 $thisEnv <environment: 0x8e86a20> $getEnv function () { return(get("thisEnv", thisEnv)) } <environment: 0x8e86a20> $getseq function () { return(get("seq", thisEnv)) } <environment: 0x8e86a20> $reverseComplement function () { print("Calling the reverseComplement function of DNASeq class") to_base <- c("A", "T", "G", "C") names(to_base) <- c("T", "A", "C", "G") trans_seq_vect <- to_base[unlist(strsplit(get("seq", thisEnv), split = ""))] trans_rev_vect <- trans_seq_vect[length(trans_seq_vect):1] newseq <- paste0(trans_rev_vect, collapse = "") return(DNASeq(newseq)) } <environment: 0x8e86a20> attr(,"class") [1] "list" "DNASeq"
得到裏面的seq屬性的值,這裏使用get得到環境中的變量的值element
get("seq", seq2$getEnv()) [1] "ATGCATGCATGCATGCATGC"
固然,若是使用這種方法生成的類,咱們得到屬性一般再也不函數外用get,由於這樣並不像面向對象的用法,咱們會在給類一個方法,某個類調用這個方法以後就能夠得到某個屬性的值,好比能夠在list中再寫一個函數,getseq,就等於get("seq", thisEnv),這樣就能夠面向對象的使用seq2$getseq()來得到seq屬性。當咱們列表中添加方法時,注意應該用遵循列表的格式,用",」分開不一樣的方法或者不一樣的值。
類中除了含有屬性外,確定還得含有方法。上面咱們講到用局部環境變量建立S3類時能夠在list裏面存放方法。固然還有一種比較廣泛的,在兩種方式建立的S3類中都能使用的建立方法的途徑。使用某方法.某類來建立某類的方法。好比print.gg就是對gg類的print的方法。可是在建立這種方法以前咱們首先得用這個方法的名字建立一個函數,這樣運行函數時首先進入這個函數,而後在函數裏面使用useMethod函數,在環境中尋找該類的該方法。雖然下面的代碼比較複雜,可是重點時看UseMethod。
# Creating methods reverseComplement <- function(object){ UseMethod("reverseComplement", object) } reverseComplement.default <- function(object){ print("The class of this object can not be found") } # Straight forward approach # # For S3 classes created by Straight forward approach reverseComplement.DNAseq <- function(object){ print("Calling the reverseComplement function of DNAseq class") ## Compelement according to the vector below to_base <- c("A", "T", "G", "C") names(to_base) <- c("T", "A", "C", "G") ## Transform long charactor to vector and complement trans_seq_vect <- to_base[unlist(strsplit(object$seq, split = ""))] ## Reverse trans_rev_vect <- trans_seq_vect[length(trans_seq_vect):1] ## Collape to long character newseq <- paste0(trans_rev_vect, collapse = "") # Return a new DNAseq class return(DNAseq(newseq)) } # For S3 classed created by local enviroment approach reverseComplement.DNASeq <- function(object){ print("Calling the reverseComplement function of DNASeq class") ## Compelement according to the vector below to_base <- c("A", "T", "G", "C") names(to_base) <- c("T", "A", "C", "G") ## Transform long charactor to vector and complement trans_seq_vect <- to_base[unlist(strsplit(get("seq", seq2$getEnv()), split = ""))] ## Reverse trans_rev_vect <- trans_seq_vect[length(trans_seq_vect):1] ## Collape to long character newseq <- paste0(trans_rev_vect, collapse = "") # Return a new DNASeq class return(DNASeq(newseq)) }
上面還有一個default函數,表示默認的方法,若是該類找不到該類匹配的方法,就會使用默認方法。
S3類可使用繼承,在原來類的基礎上再append一個新的類名即爲新的類,用NextMethod能夠調用下一層類的方法。
建立一個primer類繼承DNAseq類
#inheritance Primer <- function(seq = "ATGCATGCATGCATGCATGCGGCC"){ pr <- strtrim(seq, 20) me <- DNAseq(pr) class(me) <- append(class(me), "Primer") return(me) } Primer1 <- Primer() Primer1 $seq [1] "ATGCATGCATGCATGCATGC" $length [1] 20 attr(,"class") [1] "list" "DNAseq" "Primer"
調用方法的時候會按照從左到右的順序,再這個例子中,默認先調用DNAseq的方法,若是想要調用Primer類的方法,首先寫一個Primer的reverseComplement方法
# Creating methods reverseComplement.Primer <- function(object){ print("Running reverseComplement of Primer class") }
而後在DNAseq類中調用下一類的方法,使用NextMethod
reverseComplement.DNAseq <- function(object){ print("Calling the reverseComplement function of DNAseq class") NextMethod("reverseComplement", object) ## Compelement according to the vector below to_base <- c("A", "T", "G", "C") names(to_base) <- c("T", "A", "C", "G") ## Transform long charactor to vector and complement trans_seq_vect <- to_base[unlist(strsplit(object$seq, split = ""))] ## Reverse trans_rev_vect <- trans_seq_vect[length(trans_seq_vect):1] ## Collape to long character newseq <- paste0(trans_rev_vect, collapse = "") # Return a new DNAseq class return(DNAseq(newseq)) }
reverseComplement(Primer1) [1] "Calling the reverseComplement function of DNAseq class" [1] "Running reverseComplement of Primer class" $seq [1] "GCATGCATGCATGCATGCAT" $length [1] 20 attr(,"class") [1] "list" "DNAseq"
reverseComplement(seq1) [1] "Calling the reverseComplement function of DNAseq class" [1] "The class of this object can not be found" $seq [1] "GCATGCATGCATGCATGCAT" $length [1] 20 attr(,"class") [1] "list" "DNAseq"