함수 객체
Function object컴퓨터 프로그래밍에서 함수[a] 객체는 보통 동일한 구문(함수가 될 수도 있는 함수 매개 변수)을 사용하여 객체가 일반적인 함수인 것처럼 호출되거나 호출될 수 있는 구조입니다.함수 오브젝트는 흔히 펑터라고 불립니다.
묘사
함수 객체의 일반적인 용도는 콜백 함수를 쓰는 것입니다.C와 같은 절차 언어의 콜백은 함수 [2]포인터를 사용하여 실행할 수 있습니다.단, 콜백 함수에 대한 상태 전달 또는 콜백함수에 대한 상태 전달이 어렵거나 어색할 수 있습니다.또, 이 제한에 의해서, 기능의 보다 동적인 동작도 억제됩니다.함수 객체는 실제로 전체 객체의 외관이며 자체 상태를 전달하기 때문에 이러한 문제를 해결합니다.
C++, Eiffel, Groovy, Lisp, Smalltalk, Perl, PHP, Python, Ruby, Scala 및 기타 많은 현대(및 일부 오래된) 언어들은 1등급 함수 객체를 지원하며 심지어 그것들을 상당히 [3]사용할 수도 있다.기능 프로그래밍 언어는 추가로 폐쇄를 지원한다. 즉, 생성 시 주변 환경에서 변수를 '닫을' 수 있는 1등급 기능이다.컴파일 중에 람다 리프팅이라고 하는 변환이 폐쇄를 기능 객체로 변환합니다.
C 및 C++의 경우
콜백 함수를 사용하여 항목 쌍 간의 순서 관계를 정의하는 정렬 루틴의 예를 생각해 보십시오.다음 C 프로그램은 함수 포인터를 사용합니다.
#실패하다 <stdlib.h> /* qsort() 콜백 함수, a < b의 경우 0, a > b의 경우 > 0, a == b */의 경우 0을 반환합니다. 인트 비교 정보(컨스턴트 무효* a, 컨스턴트 무효* b) { 돌아가다 ( *(인트 *)a - *(인트 *)b ); } ... // qsort의 프로토타입은 // void qsort (표준 *베이스, size_t nel, size_t width, int (*표준)(const void *, const void *)); ... 인트 주된(무효) { 인트 항목들[] = { 4, 3, 1, 2 }; q(항목들, 크기(항목들) / 크기(항목들[0]), 크기(항목들[0]), 비교 정보); 돌아가다 0; }
C++에서는 함수 호출 연산자를 오버로드하는 클래스를 정의함으로써 일반 함수 대신 함수 객체를 사용할 수 있습니다.operator()
멤버 함수C++ 에서는, 다음과 같이 표시됩니다.
// 비교기 술어: a < b이면 true를 반환하고 그렇지 않으면 false를 반환합니다. 구조 IntComparator { 부울 교환입니다.()(컨스턴트 인트 &a, 컨스턴트 인트 &b) 컨스턴트 { 돌아가다 a < > b; } }; 인트 주된() { 표준::벡터< >인트> 항목들 { 4, 3, 1, 2 }; 표준::종류(항목들.시작한다.(), 항목들.끝.(), IntComparator()); 돌아가다 0; }
에 콜백을 제공하기 위한 구문은std::sort()
함수는 동일하지만 함수 포인터 대신 객체가 전달됩니다.호출 시 콜백 함수는 다른 멤버 함수와 마찬가지로 실행되므로 오브젝트의 다른 멤버(데이터 또는 함수)에 대한 풀액세스가 가능합니다.물론 이것은 단순한 예에 불과합니다.펑터가 일반 함수보다 더 많이 제공하는 힘을 이해하려면 특정 필드를 기준으로 객체를 정렬하는 일반적인 사용 사례를 고려하십시오.다음 예제에서는 펑터를 사용하여 각 직원의 ID 번호를 기준으로 단순 직원 데이터베이스를 정렬합니다.
구조 비교 기준 { 컨스턴트 표준::스트링 정렬_필드; 비교 기준(컨스턴트 표준::스트링& 정렬 필드="이름) : 정렬_필드(정렬 필드) { /* 확인 sort_field */ } 부울 교환입니다.()(컨스턴트 직원& a, 컨스턴트 직원& b) { 한다면 (정렬_필드 == "이름) 돌아가다 a.이름. < > b.이름.; 또 다른 한다면 (정렬_필드 == '연령') 돌아가다 a.나이 < > b.나이; 또 다른 한다면 (정렬_필드 == "idnum") 돌아가다 a.idnum(아이디넘) < > b.idnum(아이디넘); 또 다른 /* 예외나 뭐 그런 거 */ } }; 인트 주된() { 표준::벡터< >직원> 앰프; /* 코드를 사용하여 데이터베이스를 채웁니다*/ // 직원 ID 번호에 따라 데이터베이스 정렬 표준::종류(앰프.시작한다.(), 앰프.끝.(), 비교 기준("idnum")); 돌아가다 0; }
C++11에서는 람다 식을 사용하여 동일한 작업을 보다 간결하게 수행할 수 있습니다.
인트 주된() { 표준::벡터< >직원> 앰프; /* 코드를 사용하여 데이터베이스를 채웁니다*/ 컨스턴트 표준::스트링 정렬 필드 = "idnum"; 표준::종류(앰프.시작한다.(), 앰프.끝.(), [&정렬 필드](컨스턴트 직원& a, 컨스턴트 직원& b){ 필드 */를 선택하고 비교하는 /* 코드 }); 돌아가다 0; }
콜백 함수 이외의 상황에서는 함수 객체를 사용할 수 있습니다.이 경우 함수 객체에 대해서는 일반적으로 단축된 함수는 사용되지 않습니다.예시를 계속하면,
IntComparator cpm; 부울 결과 = cpm(a, b);
C++에서는 클래스 타입 펑터 외에 다른 종류의 함수 오브젝트도 사용할 수 있습니다.C++의 멤버 포인터 또는 템플릿 기능을 이용할 수 있습니다.템플릿의 표현성을 통해 다른 함수 객체(함수 구성 등)의 관점에서 함수 객체를 정의하는 등 일부 함수 프로그래밍 기술을 사용할 수 있습니다.C++ Standard Template Library(STL; 표준 템플릿 라이브러리)의 대부분은 템플릿 기반 함수 개체를 많이 사용합니다.
상태 유지
함수 객체의 또 다른 장점은 영향을 미치는 상태를 유지할 수 있다는 것입니다.operator()
콜간.예를 들어, 다음 코드는 10 이상의 제너레이터 카운트를 정의하고 11회 호출됩니다.
#실패하다 <blocks> #실패하다 <iostream> #실패하다 <반복기> 학급 발신인수 { 일반의: 발신인수(인트 세어보세요) : 카운트_(세어보세요) {} 인트 교환입니다.()() { 돌아가다 카운트_++; } 사적인: 인트 카운트_; }; 인트 주된() { 컨스턴트 인트 주(10); 표준::생성_n(표준::오스트림_이터레이터< >인트>(표준::외치다, "\n"), 11, 발신인수(주)); }
C++14 이후에서는, 상기의 예를 다음과 같이 고쳐 쓸 수 있습니다.
#실패하다 <blocks> #실패하다 <iostream> #실패하다 <반복기> 인트 주된() { 표준::생성_n(표준::오스트림_이터레이터< >인트>(표준::외치다, "\n"), 11, [세어보세요=10]() 변이 가능한 { 돌아가다 세어보세요++; }); }
인 C#
C#에서 함수 객체는 대리인을 통해 선언됩니다.대리자는 명명된 방법 또는 람다 식을 사용하여 선언할 수 있습니다.다음은 명명된 방법을 사용한 예입니다.
사용. 시스템.; 사용. System.Collections.포괄적인; 일반의 학급 비교 클래스 1 { 일반의 정적인 인트 기능 비교(인트 x, 인트 y) { 돌아가다 x - y; } 일반의 정적인 무효 주된() { 변화하다 항목들 = 신규 목록.< >인트> { 4, 3, 1, 2 }; 비교< >인트> 델 = 기능 비교; 항목들.종류(델); } }
다음은 람다 식을 사용한 예입니다.
사용. 시스템.; 사용. System.Collections.포괄적인; 일반의 학급 비교 클래스 2 { 일반의 정적인 무효 주된() { 변화하다 항목들 = 신규 목록.< >인트> { 4, 3, 1, 2 }; 항목들.종류((x, y) => x - y); } }
인 D
D는 함수 객체를 선언하는 몇 가지 방법을 제공합니다. 각각 닫힘을 통해 Lisp/Python 스타일 또는 대리인을 통해 C# 스타일입니다.
부울 발견하다(T)(T[] 건초 더미, 부울 위임하다(T) 니들_테스트) { 앞지르다 (짚; 건초 더미) { 한다면 (니들_테스트(짚)) 돌아가다 진실의; } 돌아가다 거짓의; } 무효 주된() { 인트[] 건초 더미 = [345, 15, 457, 9, 56, 123, 456]; 인트 바늘로 찌르다 = 123; 부울 니들 테스트(인트 n) { 돌아가다 n == 바늘로 찌르다; } 주장하다(발견하다(건초 더미, &니들 테스트)); }
D의 대리자와 클로저의 차이는 컴파일러에 의해 자동으로 보수적으로 결정됩니다.D는 람다 스타일의 정의를 허용하는 함수 리터럴도 지원합니다.
무효 주된() { 인트[] 건초 더미 = [345, 15, 457, 9, 56, 123, 456]; 인트 바늘로 찌르다 = 123; 주장하다(발견하다(건초 더미, (인트 n) { 돌아가다 n == 바늘로 찌르다; })); }
컴파일러가 코드를 인라인(위 참조)할 수 있도록 함수 오브젝트를 연산자 오버로드를 통해 C++-style로 지정할 수도 있습니다.
부울 발견하다(T, F)(T[] 건초 더미, F 니들_테스트) { 앞지르다 (짚; 건초 더미) { 한다면 (니들_테스트(짚)) 돌아가다 진실의; } 돌아가다 거짓의; } 무효 주된() { 인트[] 건초 더미 = [345, 15, 457, 9, 56, 123, 456]; 인트 바늘로 찌르다 = 123; 학급 니들 테스트 { 인트 바늘로 찌르다; 이것.(인트 n) { 바늘로 찌르다 = n; } 부울 opCall(인트 n) { 돌아가다 n == 바늘로 찌르다; } } 주장하다(발견하다(건초 더미, 신규 니들 테스트(바늘로 찌르다))); }
에펠에서
에펠의 소프트웨어 개발 방법과 언어에서 운영과 객체는 항상 별개의 개념으로 보입니다.그러나 에이전트 메커니즘은 작업을 런타임 개체로 모델링하는 데 도움이 됩니다.에이전트는 프로시저 콜에서 인수로 전달되거나 콜백 루틴으로 지정되는 등 함수 객체에 속하는 응용 프로그램의 범위를 충족합니다.에펠의 에이전트 메커니즘 설계는 메서드와 언어의 객체 지향적 특성을 반영하려고 합니다.에이전트는 일반적으로 두 라이브러리 클래스 중 하나의 직접 인스턴스로, 에펠에서 두 가지 유형의 루틴을 모델링합니다.PROCEDURE
그리고.FUNCTION
이 두 가지 클래스는 보다 추상적인 것에서 파생됩니다.ROUTINE
.
소프트웨어 텍스트 내에서 language 키워드agent
를 사용하면 에이전트를 콤팩트한 형식으로 구성할 수 있습니다.다음 예제에서는 버튼을 클릭했을 때 실행할 액션 목록에 게이지를 전진시키는 액션을 추가하는 것이 목표입니다.
마이버튼.선택_액션.확장하다 (대리인 my_게이지.스텝 포워드)
루틴extend
위의 예에서 참조된 것은 이벤트 구동 프로그래밍 기능을 제공하는 Graphical User Interface(GUI; 그래피컬사용자 인터페이스) 라이브러리의 클래스 기능입니다.
다른 라이브러리 클래스에서는 에이전트가 다른 목적으로 사용되는 것으로 보입니다.예를 들어, 데이터 구조를 지원하는 라이브러리에서 클래스 모델링 선형 구조는 함수와 함께 보편적 정량화에 영향을 미칩니다.for_all
타입의BOOLEAN
에이전트, 예를 들어FUNCTION
, 인수로써.다음 예에서는my_action
의 모든 멤버가 실행되는 경우에만my_list
문자 '!'를 포함합니다.
my_list: 링크드_리스트 [스트링] ... 한다면 my_list.모두 (대리인 {스트링}.가지다 ('!')) 그리고나서 my_action 끝. ...
에이전트가 생성되면 에이전트가 모델링하는 루틴에 대한 인수와 에이전트가 적용되는 대상 개체에 대한 인수를 닫거나 열어 둘 수 있습니다.닫힌 인수 및 대상에는 에이전트 생성 시 값이 지정됩니다.열린 인수 및 대상에 대한 값 할당은 에이전트가 생성된 후 어느 시점까지 연기됩니다.루틴for_all
인수로서는 구조체의 실제 범용 파라미터에 준거한 하나의 오픈 인수 또는 타깃을 가진 함수를 나타내는 에이전트를 상정합니다(STRING
를 참조해 주세요).
에이전트의 타겟이 열려 있는 경우 텍스트에 나타나듯이 오브젝트 참조를 중괄호로 둘러싸인 예상 타깃의 클래스 이름이 대체됩니다.agent {STRING}.has ('!')
를 참조해 주세요.인수가 열린 채로 있으면 물음표 문자(?)는 열린 인수의 자리 표시자로 코드화됩니다.
타깃 및 인수를 닫거나 열어둘 수 있는 기능은 에이전트 메커니즘의 유연성을 향상시키는 것을 목적으로 합니다.새 행 뒤에 표준 출력에 문자열을 인쇄하려면 다음 절차를 포함하는 클래스를 고려합니다.
print_on_new_line (s: 스트링) -- 새 행 앞에 's'를 인쇄합니다. 하다 인쇄물 (%N + s) 끝.
다음 스니펫은 같은 클래스에 있는 것으로 가정하고,print_on_new_line
에이전트에서 동일한 루틴에 대한 인수로 사용되는 오픈 인수와 오픈타깃의 혼합을 보여줍니다.
my_list: 링크드_리스트 [스트링] ... my_list.모든 것을 하다 (대리인 print_on_new_line (?)) my_list.모든 것을 하다 (대리인 {스트링}.보다 낮다) my_list.모든 것을 하다 (대리인 print_on_new_line (?)) ...
이 예에서는, 다음의 순서를 사용하고 있습니다.do_all
선형 구조의 경우 구조체의 각 항목에 대해 에이전트에 의해 모델링된 루틴을 실행합니다.
3개의 명령어 시퀀스에 따라 스트링이 출력됩니다.my_list
는 문자열을 소문자로 변환한 후 다시 인쇄합니다.
절차.do_all
open 인수 중 하나를 현재 아이템으로 대체하는 루틴을 실행하는 구조 전체에 걸쳐 반복한다(에이전트의 경우 기준).print_on_new_line
또는 오픈 타깃(에이전트의 경우,to_lower
).
open 및 closed 인수 및 타겟에서는 필요한 수 이외의 인수를 모두 닫음으로써 필요한 수보다 많은 인수를 호출하는 루틴도 사용할 수 있습니다.
my_list.모든 것을 하다 (대리인 my_multi_multiple_multiple_multiple (closed_closed_1, ?, closed_closed_2, closed_closed_3)
Effel 에이전트 메커니즘은 Effel ISO/ECMA 표준 문서에 자세히 설명되어 있습니다.
자바어
자바에는 퍼스트 클래스 함수가 없기 때문에 함수 오브젝트는 보통 단일 메서드로 인터페이스에 의해 표현됩니다(가장 일반적으로는Callable
interface)는 일반적으로 어나니머스 내부 클래스 또는 Java 8부터는 람다로 구현됩니다.
Java의 표준 라이브러리의 예를 들자면,java.util.Collections.sort()
를 취득하다List
목록 내의 객체를 비교하는 역할을 하는 펑터도 있습니다.퍼스트 클래스 기능이 없으면 이 함수는 Comparator 인터페이스의 일부입니다.이것은 다음과 같이 사용할 수 있습니다.
목록.< >스트링> 목록. = 어레이.리스트("10", "1", "20", "11", "21", "12"); 비교기< >스트링> numStringComparator = 신규 비교기< >스트링>() { 일반의 인트 비교하다(스트링 str1, 스트링 str2) { 돌아가다 정수.값(str1).비교 대상(정수.값(str2)); } }; 컬렉션.종류(목록., numStringComparator);
Java 8+ 에서는, 다음과 같이 기술할 수 있습니다.
목록.< >스트링> 목록. = 어레이.리스트("10", "1", "20", "11", "21", "12"); 비교기< >스트링> numStringComparator = (str1, str2) -> 정수.값(str1).비교 대상(정수.값(str2)); 컬렉션.종류(목록., numStringComparator);
자바스크립트
JavaScript에서 함수는 퍼스트 클래스 객체입니다.JavaScript는 클로저도 지원합니다.
다음을 후속 Python 예시와 비교해 보십시오.
기능. 어큐뮬레이터(개시하다) { 변화하다 현재의 = 개시하다; 돌아가다 기능. (x) { 돌아가다 현재의 += x; }; }
사용중인 예를 다음에 나타냅니다.
변화하다 a = 어큐뮬레이터(4); 변화하다 x = a(5); // x의 값은 9입니다. x = a(2); // x의 값은 11입니다. 변화하다 b = 어큐뮬레이터(42); x = b(7); // x의 값은 49(폐쇄 b의 경우 전류 = 49)입니다. x = a(7); // x의 값은 18(폐쇄 a의 전류 = 18)입니다.
줄리아에서
Julia에서는 메서드가 유형과 연관되어 있으므로 임의의 Julia 오브젝트의 유형에 메서드를 추가하여 임의의 Julia 오브젝트를 "호출 가능"하게 할 수 있습니다.(이러한 「콜 가능한」오브젝트는, 「함수」라고 불리는 경우가 있습니다).
이 어큐뮬레이터 변이 구조(Paul Graham의 프로그래밍 언어 구문 및 [4]명확성 연구에 기초함)가 그 예입니다.
줄리아.> 가변 구조 어큐뮬레이터 n::내부 끝. 줄리아.> 기능. (액세스::어큐뮬레이터)(n2) 액세스.n += n2 끝. 줄리아.> a = 어큐뮬레이터(4) 어큐뮬레이터(4) 줄리아.> a(5) 9 줄리아.> a(2) 11 줄리아.> b = 어큐뮬레이터(42) 어큐뮬레이터(42) 줄리아.> b(7) 49
이러한 축전지는 폐쇄를 사용하여 구현할 수도 있습니다.
줄리아.> 기능. 어큐뮬레이터(n0) n = n0 기능.(n2) n += n2 끝. 끝. 어큐뮬레이터 (포괄적인 기능. 와 함께 1 방법) 줄리아.> a = 어큐뮬레이터(4) (::#1) (1가지 방법으로 기능 확장) 줄리아.> a(5) 9 줄리아.> a(2) 11 줄리아.> b = 어큐뮬레이터(42) (::#1) (1가지 방법으로 기능 확장) 줄리아.> b(7) 49
lisp 및 scheme의 경우
Common Lisp, Scheme 등의 Lisp 패밀리 언어에서 함수는 문자열, 벡터, 목록 및 숫자와 마찬가지로 객체입니다.클로저 구축 연산자는 프로그램의 일부로부터 함수 객체를 생성한다: 연산자에게 인수로서 주어지는 코드의 일부는 함수의 일부이며, 어휘 환경도 마찬가지이다: 어휘적으로 가시적인 변수의 바인딩을 캡처하여 함수 객체에 저장한다.캡처된 바인딩은 C++의 연산자()와 마찬가지로 멤버 변수의 역할을 하며 클로저의 코드 부분은 익명 멤버 함수의 역할을 합니다.
폐쇄 생성자에는 다음과 같은 구문이 있습니다.(lambda (parameters ...) code ...)
.그(parameters ...)
part를 사용하면 인터페이스를 선언할 수 있으므로 함수는 선언된 파라미터를 취득할 수 있습니다.그code ...
functor가 호출될 때 평가되는 식으로 구성됩니다.
C++와 같은 언어에서 함수의 많은 사용은 누락된 폐쇄 생성자의 에뮬레이션에 불과합니다.프로그래머는 폐쇄를 직접 구성할 수 없기 때문에 필요한 상태 변수와 멤버 함수를 모두 포함하는 클래스를 정의해야 합니다.그런 다음 모든 멤버 변수가 생성자를 통해 초기화되도록 해당 클래스의 인스턴스를 대신 구성하십시오.값은 폐쇄에 의해 직접 캡처되어야 하는 지역 변수에서 정확하게 도출됩니다.
클래스 시스템을 사용하는 함수 객체, 폐쇄 사용 안 함:
(디클래스 계산대 () ((가치 : initarg : 값 : 악세사리 가치의))) (디프로덕트 함수 호출 ((c 계산대)) (인시프 (가치의 c))) (삭제하다 제조 카운터 (초기값) (제조법 카운터 : 값 초기값)) ;;; 카운터를 사용합니다. (디파이브 *c* (제조 카운터 10)) (함수 호출 *c*) --> 11 (함수 호출 *c*) --> 12
Lisp에서는 funcallable 객체를 만드는 표준 방법이 없기 때문에 FUNCTOR-CALL이라는 범용 함수를 정의하여 가짜로 만듭니다.이것은 어떤 클래스에나 특화할 수 있습니다.표준 FUNCALL 함수는 범용 함수가 아니라 함수 객체만 사용합니다.
이 FUNCTOR-CALL 범용 함수는 함수 객체를 제공합니다.이것은 일반적인 함수인 것처럼 호출하거나 호출할 수 있는 컴퓨터 프로그래밍 구조이며, 일반적으로 동일한 구문을 사용합니다.구문은 거의 동일합니다.FUNCALL이 아닌 FUNCTOR-CALL입니다.일부 Lisps는 단순한 확장으로 재미있는 호출 가능한 객체를 제공합니다.함수와 동일한 구문을 사용하여 객체를 호출할 수 있도록 하는 것은 매우 간단한 일입니다.함수 호출 연산자가 클래스 오브젝트든 닫힘이든 상관 없이 다양한 종류의 함수에서 작업하도록 하는 것은 정수, 실수, 복소수 등 다른 종류의 번호로 작업하는 + 연산자를 만드는 것만큼 복잡하지 않습니다.
이제 클로저를 사용하여 카운터를 구현했습니다.이것은 훨씬 더 간단하고 직접적이다.MAKE-COUNTER 공장 함수의 INITIAL-VALUE 인수가 캡처되어 직접 사용됩니다.생성자를 통해 일부 보조 클래스 개체로 복사할 필요가 없습니다.카운터입니다.보조 객체가 생성되지만 이 작업은 백그라운드에서 수행됩니다.
(삭제하다 제조 카운터 (가치) (람다 () (인시프 가치))) ;;; 카운터를 사용합니다. (디파이브 *c* (제조 카운터 10)) (펑콜 *c*) ; --> 11 (펑콜 *c*) ; --> 12
스킴은 폐쇄를 더욱 단순하게 하며 스킴 코드는 이러한 고차 프로그래밍을 다소 더 관용적으로 사용하는 경향이 있습니다.
(정의하다(제조 카운터 가치) (람다() (세트!가치 (+가치 1)) 가치)) ;;; 카운터를 사용합니다. (정의하다c (제조 카운터 10)) (c) ; --> 11 (c) ; --> 12
동일한 어휘 환경에서 두 개 이상의 폐쇄를 생성할 수 있습니다.각각 특정 종류의 연산을 구현하는 폐쇄 벡터는 가상 연산을 가진 객체를 매우 충실하게 에뮬레이트할 수 있습니다.이러한 유형의 단일 디스패치 객체 지향 프로그래밍은 클로징으로 완전히 수행할 수 있습니다.
그래서 유명한 산의 양쪽에서 일종의 터널이 파여 있다.OOP 언어의 프로그래머는 객체의 기능적 목적을 수행하기 위한 하나의 주요 기능을 갖도록 객체를 제한함으로써 함수 객체를 발견하고 객체가 호출되는 것처럼 보이도록 이름을 삭제합니다.폐쇄를 사용하는 프로그래머는 객체가 함수처럼 호출되는 것에 놀라지 않지만, 동일한 환경을 공유하는 여러 폐쇄가 단일 디스패치 유형의 OOP에 대한 가상 테이블과 같은 추상적인 연산 세트를 제공할 수 있음을 알게 됩니다.
목표-C에서
Objective-C에서 함수 오브젝트를 생성할 수 있습니다.NSInvocation
class. 함수 객체를 구축하려면 메서드 서명, 대상 객체 및 대상 셀렉터가 필요합니다.다음은 현재 개체의 호출을 만드는 예입니다.myMethod
:
// 함수 객체 생성 셀 셀 = @parames(@parames)(myMethod(마이메서드)); NSInvocation* 초대하다 = [NSInvocation 호출Method Signature 사용: [자신 method Signature For Selector:셀]]; [초대하다 set Target(대상 설정):자신]; [초대하다 set Selector:셀]; // 실제 호출 실행 [초대하다 호출하다];
장점NSInvocation
타겟 오브젝트는 작성 후 변경할 수 있습니다.싱글NSInvocation
예를 들어 관찰 가능한 객체에서 임의의 수의 타깃에 대해 작성한 후 호출할 수 있습니다.안NSInvocation
프로토콜에서만 생성할 수 있지만 간단하지 않습니다.여기 보세요.
인펄
Perl에서 함수 객체는 객체의 인스턴스 데이터에 대해 닫힌 함수를 반환하는 클래스의 생성자에서 생성될 수 있으며, 클래스에는 다음과 같은 복이 있습니다.
패키지 액세스 1; 후보선수 신규 { 나의 $클래스 = 교대하다; 나의 $140 = 교대하다; 나의 $obj = 후보선수 { 나의 $num = 교대하다; $140 += $num; }; 축복하다 $obj, $클래스; } 1;
또는 과부하로 인해&{}
연산자를 사용하여 객체를 함수로 사용할 수 있습니다.
패키지 Acc2; 사용하다 과부하 '&{}' => 후보선수 { 나의 자기 부담 = 교대하다; 후보선수 { 나의 $num = 교대하다; 자기 부담->{arg} += $num; } }; 후보선수 신규 { 나의 $클래스 = 교대하다; 나의 $140 = 교대하다; 나의 $obj = { arg => $140 }; 축복하다 $obj, $클래스; } 1;
어느 경우든 함수 오브젝트는 참조 화살표 구문 $ref->(@arguments) 중 하나를 사용하여 사용할 수 있습니다.
사용하다 액세스 1; 나의 $a = 액세스 1->신규(42); 인쇄물 $a->(10), "\n"; 인쇄수 52 인쇄물 $a->(8), "\n"; 인쇄수 60
또는 coderef dereferencing 구문 &$ref(@ref)를 사용합니다.
사용하다 Acc2; 나의 $a = Acc2->신규(12); 인쇄물 &$a(10), "\n"; 인쇄수 22 인쇄물 &$a(8), "\n"; 인쇄수 30
PHP의 경우
PHP 5.3+에는 예를 들어 usort() 함수의 파라미터로 사용할 수 있는 퍼스트 클래스 함수가 있습니다.
$a = 배열(3, 1, 4); 사용하다($a, 기능. (x달러, $y) { 돌아가다 x달러 - $y; });
PHP 5.3+는 람다 함수와 폐쇄도 지원합니다.
기능. 어큐뮬레이터($start) { 현재 $current($current) = $start; 돌아가다 기능.(x달러) 사용하다(&현재 $current($current)) { 돌아가다 현재 $current($current) += x달러; }; }
사용중인 예를 다음에 나타냅니다.
$a = 어큐뮬레이터(4); x달러 = $a(5); 메아리치다 "x =x달러<br/>"; // x = 9 x달러 = $a(2); 메아리치다 "x =x달러<br/>"; // x = 11
또한 PHP 5.3+에서는 [5]magic __invoke() 메서드를 클래스에 추가하여 오브젝트를 호출할 수 없게 할 수도 있습니다.
학급 마이너스 { 일반의 기능. __개요(x달러, $y) { 돌아가다 x달러 - $y; } } $a = 배열(3, 1, 4); 사용하다($a, 신규 마이너스());
PowerShell의 경우
윈도우즈 PowerShell 언어에서 스크립트 블록은 단일 단위로 사용할 수 있는 문 또는 표현식의 모음입니다.스크립트 블록은 인수를 받아들여 값을 반환할 수 있습니다.스크립트 블록은 Microsoft 인스턴스입니다.NET Framework 유형 시스템.관리.자동화스크립트 블록
기능. Get-Accumulator(집적기)(x달러) { { PARAM.($y) 돌아가다 x달러 += $y }.Get New Closure(신규 클로저)() }
PS C:\>$a = Get-Accumulator(집적기) 4 PS C:\>& $a 5 9 PS C:\>& $a 2 11 PS C:\>b달러 = Get-Accumulator(집적기) 32 PS C:\>& b달러 10 42
Python의 경우
Python에서 함수는 문자열, 숫자, 목록 등과 같이 1등급 객체입니다.이 기능을 사용하면 대부분의 경우 함수 개체를 쓸 필요가 없습니다.를 가진 임의의 오브젝트__call__()
메서드는 function-call 구문을 사용하여 호출할 수 있습니다.
예를 들어 다음과 같은 어큐뮬레이터 클래스가 있습니다(Paul Graham의 프로그래밍 언어 구문 및 [6]명확성 연구에 기초함).
학급 어큐뮬레이터: 방어하다 __init__(자신, n) -> 없음.: 자신.n = n 방어하다 __call__(자신, x): 자신.n += x 돌아가다 자신.n
(인터랙티브인터프리터 사용) 사용 예:
>>>a = 어큐뮬레이터(4) >>>a(5) 9 >>>a(2) 11 >>>b = 어큐뮬레이터(42) >>>b(7) 49
함수는 객체이기 때문에 다음 예에서 보듯이 로컬로 정의하거나 Atribut을 지정하거나 다른 함수에 의해 반환할 수도 있습니다.
방어하다 어큐뮬레이터(n): 방어하다 주식회사(x): 로컬이 아닌 n n += x 돌아가다 n 돌아가다 주식회사
인루비
Ruby에서는 여러 오브젝트, 특히 메서드와 Proc 오브젝트를 함수 오브젝트로 간주할 수 있습니다.Ruby는 또한 반기능적인 오브젝트로 생각할 수 있는2종류의 오브젝트를 가지고 있습니다.Unbound Method 및 블록.UnboundMethods를 함수 개체로 사용하려면 먼저 개체에 바인딩해야 합니다(따라서 메서드가 됩니다).블록은 함수 객체와 마찬가지로 호출할 수 있지만 다른 용량에서 객체(예를 들어 인수로 전달됨)로 사용하려면 먼저 Proc로 변환해야 합니다.최근에는 기호(리터럴 단항 표시기를 통해 액세스):
)는, 다음과 같이 변환할 수도 있습니다.Proc
s. 루비의 유니리 사용&
오퍼레이터: 콜에 대응합니다.to_proc
루비 익스텐션프로젝트는 단순한 해킹을 만들었습니다.
학급 기호. 방어하다 행선지 프로세서 { obj, *args obj.보내세요(자신, *args) } 끝. 끝.
자, 방법foo
기능 객체가 될 수 있습니다.Proc
, 경유&:foo
를 통해 사용됩니다.takes_a_functor(&:foo)
.Symbol.to_proc
2006년 6월 11일 RubyKaigi2006에서 루비에 공식적으로 추가되었습니다.[1]
형식이 다양하기 때문에 펑터라는 용어는 일반적으로 Ruby에서 함수 개체를 의미하기 위해 사용되지 않습니다.Ruby Facets 프로젝트에 의해 도입된 디스패치 위임의 종류만 Functor로 명명됩니다.가장 기본적인 정의는 다음과 같습니다.
학급 펑터 방어하다 초기화하다(&기능하다) @func = 기능하다 끝. 방어하다 method_module(동작, *args, &흐릿) @func.불러(동작, *args, &흐릿) 끝. 끝.
이 사용법은 ML과 같은 함수형 프로그래밍 언어 및 원래 수학 용어에서 사용되는 것과 더 유사합니다.
다른 의미
보다 이론적인 맥락에서 함수 객체는 함수 클래스의 인스턴스로 간주될 수 있으며, 특히 함수가 1등급 객체인 Common Lisp와 같은 언어에서는 더욱 그렇습니다.
기능 프로그래밍 언어의 ML 제품군은 모듈에서 모듈로 또는 유형에서 유형으로 매핑을 나타내기 위해 펑터(functor)라는 용어를 사용하며 코드를 재사용하는 기술입니다.이러한 방식으로 사용되는 함수는 범주 이론에서 함수의 원래 수학적 의미 또는 C++, Java 또는 Ada에서 일반 프로그래밍을 사용하는 것과 유사합니다.
Haskell에서는 범주 이론에서 펑터라는 용어가 펑터의 의미와 관련된 개념에 사용되기도 합니다.
Prolog 및 관련 언어에서 functor는 함수 기호와 동의어입니다.
「 」를 참조해 주세요.
메모들
레퍼런스
- ^ 펑토이드와 펑터의 차이점은 무엇입니까?
- ^ Silan Liu. "C++ Tutorial Part I - Basic: 5.10 Function pointers are mainly used to achieve call back technique, which will be discussed right after". TRIPOD: Programming Tutorials Copyright © Silan Liu 2002. Retrieved 2012-09-07.
Function pointers are mainly used to achieve call back technique, which will be discussed right after.
- ^ Paweł Turlejski (2009-10-02). "C++ Tutorial Part I - Basic: 5.10 Function pointers are mainly used to achieve call back technique, which will be discussed right after". Just a Few Lines. Retrieved 2012-09-07.
PHP 5.3, along with many other features, introduced closures. So now we can finally do all the cool stuff that Ruby / Groovy / Scala / any_modern_language guys can do, right? Well, we can, but we probably won’t… Here's why.
- ^ 어큐뮬레이터 제너레이터
- ^ Magic 메서드에 관한 PHP 문서
- ^ 어큐뮬레이터 제너레이터
- ^ Python 참조 설명서 - 함수 정의
추가 정보
- David Vandevoorde & Nicolai M Josuttis (2006).C++ 템플릿: 전체 가이드, ISBN 0-201-73484-2: 특히 22장은 기능 객체에 대해 다루고 있습니다.
외부 링크
- Portland Pattern Repository의 설명
- C++ 어드밴스드 설계의 문제 - 비동기 C++ by Kevlin Henney
- Lars Haendel의 함수 포인터 튜토리얼(2000/2001)
- Herb Sutter의 '일반화된 기능 포인터' 기사
- Java용 범용 알고리즘
- PHP 펑터 - PHP의 함수 개체
- Functionoid란 무엇이며, 왜 Functionoid를 사용해야 합니까? (C++ FAQ)