2012-08-24 15 views
7

Liên quan đến câu hỏi this, nhưng hơi khác và hy vọng rõ ràng hơn.Việc gửi kiểu S3 cho các đối tượng S3 sử dụng các định nghĩa phương thức chính thức

Tôi đang tìm kiếm sạch cách đăng ký chính thức các phương thức cho cả lớp S4 và S3, nhưng không dựa vào lược đồ đặt tên S3-dot khủng khiếp để gửi đi. Một ví dụ:

setClass("foo"); 
setClass("bar"); 

setGeneric("test", function(x, ...){ 
    standardGeneric("test"); 
}); 

setMethod("test", "bar", function(x, ...){ 
    return("success (bar)."); 
}); 

obj1 <- 123; 
class(obj1) <- "bar"; 
test(obj1); 

Ví dụ này cho thấy cách chúng ta có thể đăng ký một phương pháp test cho các đối tượng S3 của lớp bar, mà không cần phải đặt tên cho chức năng test.bar, đó là rất tốt. Tuy nhiên, giới hạn là nếu chúng ta đăng ký các phương thức theo cách này, chúng sẽ chỉ được gửi đến lớp S3 đầu tiên của đối tượng. Ví dụ:

obj2 <- 123; 
class(obj2) <- c("foo", "bar"); 
test(obj2); 

Điều này không hiệu quả, vì cách gửi phương thức S4 sẽ chỉ thử lớp foo và các lớp siêu hạng của nó. Làm thế nào ví dụ này có thể được mở rộng để nó sẽ tự động chọn phương pháp test cho bar khi không tìm thấy phương pháp thích hợp cho foo? Ví dụ. Phong cách gửi S3 nhưng không phải quay lại đặt tên cho mọi thứ test.footest.bar?

Tóm lại: làm thế nào để tạo một hàm tổng quát sử dụng phương thức chính thức gửi đi, nhưng ngoài ra trở lại lớp thứ hai, thứ ba, vv của đối tượng cho đối tượng S3 với nhiều lớp.

Trả lời

2

Bạn có thể viết một phương pháp

test = function(x, ...) UseMethod("test") 

setGeneric("test") 

.redispatch = function(x, ...) 
{ 
    if (is.object(x) && !isS4(x) && length(class(x)) != 1L) { 
     class(x) = class(x)[-1] 
     callGeneric(x, ...) 
    } else callNextMethod(x, ...) 
} 

setMethod(test, "ANY", .redispatch) 

Nhưng cá nhân tôi sẽ không trộn S3 và S4 theo cách này.

+0

Có, tôi đã làm điều gì đó tương tự; Tuy nhiên thực tế là bạn đang thực sự thay đổi thuộc tính lớp của x dọc theo cách có thể có tác dụng phụ không mong muốn ... Có cách nào bạn có thể gửi nó đến phương thức tiếp theo mà không sửa đổi đối tượng không? – Jeroen

+0

Tôi không có câu trả lời cho bạn; Tôi nghĩ rằng phương pháp S4 cho 'bar' làm việc trên một thanh 'lớp' S3 là một tai nạn của việc thực hiện, và bạn đang xây dựng một cấu trúc phức tạp trên nền móng rất run rẩy. –

3

?setOldClass sẽ cho câu trả lời:

setOldClass(c("foo", "bar")) 

setGeneric("test", function(x, ...)standardGeneric("test")) 
setMethod("test", "bar", function(x, ...)return("success (bar).")) 
+0

Vì vậy, đây chính xác là * không * những gì tôi muốn. Nó đòi hỏi một kế thừa chính thức giữa các lớp "foo" và "bar", có thể không phải như vậy. Tôi muốn nó làm việc cho bất kỳ đối tượng tùy ý với class = [x, "bar"] cho x = bất cứ điều gì, mà không cần phải khai báo thừa kế giữa x và "bar" cho mọi lớp có thể x. Giả sử ai đó đã tạo ra một đối tượng với các lớp ["zoo", "bar"], thì hàm 'test()' phải đủ thông minh để chọn phương thức cho "bar". – Jeroen