2011-08-21 129 views
8

我只是想知道是否有辦法強制函數只接受某些數據類型,而不必在函數內檢查它;或者,這是不可能的,因爲R的類型檢查是在運行時完成的(與編譯期間完成類型檢查的Java等編程語言相反)?強制特定數據類型作爲函數的參數

例如,在Java中,必須指定一個數據類型:

class t2 { 
    public int addone (int n) { 
     return n+1; 
    } 
} 

在R,類似的功能可能是

addone <- function(n) 
{ 
    return(n+1) 
} 

但如果一個矢量被提供,載體將(顯然)被退回。如果你只想要一個整數被接受,然後是做有函數內的一個條件的唯一途徑,沿

addone <- function(n) 
{ 
    if(is.vector(n) && length(n)==1) 
    { 
    return(n+1) 
    } else 
    { 
    return ("You must enter a single integer") 
    } 
} 

致謝線,
克里斯

+3

作爲代碼樣式點,在沒有標量數的情況下,您可能想拋出一個錯誤(使用'stop'或'stopifnot')或給出警告(使用'warning')不僅僅是返回一個字符串。 –

回答

16

這是完全有可能的使用S3類。您的示例在上下文或R中有些人爲設計,因爲我無法想出爲什麼要創建單個值的類的實際原因。儘管如此,這是可能的。作爲額外的好處,我演示瞭如何使用函數addone將數值1添加到數字向量(平凡)和字符向量(所以A變爲B等):

首先創建一個通用S3方法addone,utlising的S3發貨機構UseMethod

addone <- function(x){ 
    UseMethod("addone", x) 
} 

接下來,創建做作類single,其定義爲無論傳遞給它的第一個元素:

as.single <- function(x){ 
    ret <- unlist(x)[1] 
    class(ret) <- "single" 
    ret 
} 

現在創建米方法來處理各種類。默認的方法將被稱爲除非特定類被定義:

addone(1:5) 
[1] 2 3 4 5 6 

addone(as.single(1:5)) 
[1] 2 
attr(,"class") 
[1] "single" 

addone("abc") 
[1] "bcd" 

一些額外的信息:

  1. addone.default <- function(x) x + 1 
    addone.character <- function(x)rawToChar(as.raw(as.numeric(charToRaw(x))+1)) 
    addone.single <- function(x)x + 1 
    

    最後,一些示例數據測試它哈德利的devtools wiki是一切有關信息的寶貴來源,包括the S3 object system

  2. S3方法不提供嚴格的輸入。它很容易被濫用。要獲得更加嚴格的面向對象,請參閱S4 classesreference based classesproto package,瞭解Prototype基於對象的編程。

+0

S4類是一個好主意。特別是'setMethod'。 – Owen

+1

是的,S3類只處理第一個參數。 ...和'single'可能不是最好的名字 - 已經有'single'類(單精度浮點數)和'as.single'等 - 但它已被棄用。 – Tommy

4

你可以寫一個包裝類似如下:

check.types = function(classes, func) { 
    n = as.name 

    params = formals(func) 
    param.names = lapply(names(params), n) 

    handler = function() { } 
    formals(handler) = params 

    checks = lapply(seq_along(param.names), function(I) { 
     as.call(list(n('assert.class'), param.names[[I]], classes[[I]])) 
    }) 
    body(handler) = as.call(c(
     list(n('{')), 
     checks, 
     list(as.call(list(n('<-'), n('.func'), func))), 
     list(as.call(c(list(n('.func')), lapply(param.names, as.name)))) 
    )) 

    handler 
} 

assert.class = function(x, cls) { 
    stopifnot(cls %in% class(x)) 
} 

而且使用它像

f = check.types(c('numeric', 'numeric'), function(x, y) { 
    x + y 
}) 

> f(1, 2) 
[1] 3 

> f("1", "2") 
Error: cls %in% class(x) is not TRUE 

由R沒有裝飾製造略感不便。這是一種哈克 ,它從一些嚴重的問題受到影響:

  1. 你輸了懶惰的評價,因爲您必須評估參數確定 其類型。

  2. 您仍然無法檢查類型,直到通話時間;真正的靜態類型檢查 可以讓您檢查甚至從未實際發生過的呼叫的類型。

由於R使用懶評價;(2)可能使因爲呼叫可能不會實際發生,直到很晚,或從未型不檢查是非常有用的, 。

(2)的答案是添加靜態類型信息。你可能可以通過轉換表達式來做到這一點,但我不認爲你想去那裏。

3

我發現stopifnot()對於這些情況也非常有用。

x <- function(n) { 
stopifnot(is.vector(n) && length(n)==1) 
print(n) 
} 

它是如此有用的原因是因爲它提供了一個非常明確的錯誤消息給用戶,如果條件爲false。

+2

請注意,這可以寫成'stopifnot(is.vector(n),length(n)== 1)',這樣做的好處是,如果失敗,那麼失敗的兩個條件中的哪一個將顯示爲錯誤消息。 –

+0

謝謝,我總是忘記,如果不是......條件是真的,那就停止。 –

相關問題