Menu
CoddyTech

الدوال العامة وUseMethod

جزء من قسم البرمجة كائنية التوجه في رحلة R على Coddy. الدرس 7 من 57.

‏الدالة العامة هي دالة يكون متنها UseMethod("name"). عند استدعائها، تنظر إلى فئة وسيطها الأول وتستدعي الطريقة name.class. تعمل print() وformat() بهذه الطريقة؛ ويمكنك كتابة دوال عامة خاصة بك أيضًا:

speak <- function(x) UseMethod("speak")
speak.dog <- function(x) paste(x$name, "says woof")
speak.cat <- function(x) paste(x$name, "says meow")
rex <- structure(list(name = "Rex"), class = "dog")
tom <- structure(list(name = "Tom"), class = "cat")
print(speak(rex))
print(speak(tom))

الناتج:

[1] "Rex says woof"
[1] "Tom says meow"

يكتب المستدعي استدعاءً واحدًا، ويستجيب كل كائن بطريقته الخاصة. هذا هو تعدد الأشكال: لا يحتاج الكود الذي يكرّر عبر قائمة مختلطة إلى if لكل صنف:

speak <- function(x) UseMethod("speak")
speak.dog <- function(x) paste(x$name, "says woof")
speak.cat <- function(x) paste(x$name, "says meow")
pets <- list(structure(list(name = "Rex"), class = "dog"),
             structure(list(name = "Tom"), class = "cat"),
             structure(list(name = "Bo"), class = "dog"))
for (p in pets) cat(speak(p), "\n")

الناتج:

Rex says woof 
Tom says meow 
Bo says woof 

تأخذ الطريقة وسائط الدالة العامة. أضف إلى الدالة العامة وسيطًا ... كي تتمكن الطرق من قبول وسائط إضافية خاصة بها، مثل digits للدائرة:

area <- function(shape, ...) UseMethod("area")
area.square <- function(shape, ...) shape$side^2
area.circle <- function(shape, digits = 2, ...) round(pi * shape$r^2, digits)
sq <- structure(list(side = 3), class = "square")
ci <- structure(list(r = 1), class = "circle")
print(area(sq))
print(area(ci))
print(area(ci, digits = 4))

الناتج:

[1] 9
[1] 3.14
[1] 3.1416

تُمرّر UseMethod() الاستدعاء إلى الطريقة ولا تعود أبدًا: ما تُرجعه الطريقة هو نتيجة الدالة العامة، ولا يُنفَّذ الكود بعد UseMethod(). لذلك تتكوّن الدالة العامة من سطر واحد:

size <- function(x) {
  UseMethod("size")
  cat("this line never runs\n")
}
size.box <- function(x) x$w * x$h
b <- structure(list(w = 2, h = 5), class = "box")
print(size(b))

الناتج:

[1] 10
challenge icon

التحدي

سهل

تُقسَّم الأشكال على ثلاثة ملفات. أكمل الدالة العامة area() في Shape.R، ثم أضف الطريقتين area.circle() (ط π مضروبًا في مربع نصف القطر) في Circle.R وarea.rectangle() (العرض مضروبًا في الارتفاع) في Rectangle.R. المُنشئات مُعطاة.

يقرأ الكود المقدَّم أسطرًا مثل circle 2 أو rectangle 3 4، ويطبع فئة كل شكل ومساحته بمنزلتين عشريتين: circle: 12.57.

ضع الكود في Shape.R وCircle.R وRectangle.R. يحتوي main.R على كود الإدخال/الإخراج المقدَّم، ولا يمكن تعديله.

جرّب بنفسك

source("Shape.R")
source("Circle.R")
source("Rectangle.R")

# كود الإدخال/الإخراج المزوّد: اتركه كما هو
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  s <- if (p[1] == "circle") new_circle(as.numeric(p[2])) else new_rectangle(as.numeric(p[2]), as.numeric(p[3]))
  cat(sprintf("%s: %.2f", class(s), area(s)), "\n", sep = "")
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم R عبر الإنترنت