문제

나는 많은 사람들이 그 단어를 사용한다는 것을 알았습니다 폐쇄 그리고 차단하다 상호 교환 적으로. 이 사람들의 대부분은 그들이 말하는 것을 설명 할 수 없습니다.

일부 Java 프로그래머 (정말 비싼 컨설턴트)는 익명의 내부 클래스에 대해 "블록"및 "클로저"로 이야기하지만 이것이 사실이 아니라는 것을 알고 있습니다. (정의 된 방법의 범위에서 변수 변수를 전달할 수 없습니다 ...)

내가 찾고 있어요:

  • 정확한 컴퓨터 과학 블록의 정의
  • 정확한 컴퓨터 과학 폐쇄의 정의
  • 그리고 차이에 대한 설명 둘 사이.

정말 링크, 기사 또는 책을보고 싶어요 이것에 대한 참조하십시오.

도움이 되었습니까?

해결책

a 차단하다 진술과 선언으로 구성 할 수있는 코드 일뿐입니다. 폐쇄 실제 일류 객체이며, 그 값으로 블록을 갖는 실제 변수입니다.

주요 차이점은 블록이 단순히 지시를 함께 그룹화한다는 것입니다 (예 : 본체 동안 명령문), 폐쇄는 실행할 수있는 일부 코드를 포함하는 변수입니다.

폐쇄가있는 경우 일반적으로 함수로 매개 변수로 전달할 수 있습니다.

Closure c = { println 'Hello!' }
/* now you have an object that contains code */
c.call()

물론 클로즈는 더 강력하고 변수이며 객체의 사용자 지정 동작을 정의하는 데 사용될 수 있습니다 (일반적으로 사용해야했습니다. 인터페이스 또는 프로그래밍에서 다른 OOP 접근).

당신은 생각할 수 있습니다 폐쇄 해당 기능 자체가 수행하는 기능을 포함하는 함수로서.

블록은 변수의 범위를 허용하기 때문에 유용합니다. 일반적으로 범위 내에서 변수를 정의하면 문제없이 외부 정의를 무시할 수 있으며 블록 실행 중에 새로운 정의가 존재합니다.

for (int i = 0; i < 10; ++i)
{
     int t = i*2;
     printf("%d\r\n", t);
}

t 블록 내부에 정의됩니다 (의 본문 for 성명서) 그리고 그 블록 바로 안에서 지속됩니다.

다른 팁

블록은 구문 적 - 논리적 진술 단위 (더 많은 관련이 있습니다. 범위 보다 폐쇄).

if (Condition) {
    // Block here 
} 
else {
    // Another block
}

폐쇄는 anoymous 함수 또는 클래스와 관련이 있습니다 - 익명 (함수) 객체, 변수와 함께 환경에 묶인 코드 조각.

def foo() {
   var x = 0
   return () => { x += 1; return x }
}

여기 foo 폐쇄를 반환합니다! 로컬 변수 x 후에도 폐쇄를 통해 지속됩니다 foo 반환 된 익명 기능의 호출을 통해 종료되고 증가 할 수 있습니다.

val counter = foo()
print counter() // Returns 2
print counter() // Return 3

Ruby가 블록이 전화 한 이후로 블록과 폐쇄가 비슷하게 처리되는 루비 일뿐입니다. a 폐쇄:

(1..10).each do |x|
    p x
end

거기 each-Method는 폐쇄 함수 (매개 변수 x를 복용)가 전달됩니다. 차단하다 루비에서.

여러 정의가있는 용어가 있기 때문에 여기에는 많은 혼란이 있으며, 일반적으로 함께 발견되기 때문에 단순히 혼란에 빠지는 여러 가지 독특한 것들이 있기 때문입니다.

먼저 "블록"이 있습니다. 예를 들어 루프의 본문 인 유닛을 만드는 어휘의 덩어리 일뿐입니다. 언어에 실제로 블록 범위가있는 경우 해당 코드 덩어리 안에만 존재하는 변수를 정의 할 수 있습니다.

둘째, 값 유형으로 호출 가능한 코드가 있습니다. 함수 언어에서는이 기능 값이 "Funs", "익명 함수"라고 불리는 기능 값입니다 (함수는 할당 된 이름이 아니라 값에서 찾을 수 있기 때문에 이름이 필요하지 않음). lambdas "(교회의 람다 미적분학에서 그들을 만들 때 사용 된 운영자). 그것들은 "클로저"라고 불릴 수 있지만 자동으로 진정한 폐쇄는 아닙니다. 자격을 갖추려면 생성을 둘러싼 어휘 범위를 캡슐화해야합니다 (즉, 함수 자체의 범위 외부에 정의 된 변수는 함수의 범위 내에서 함수가 호출 될 때마다 사용할 수 있습니다. 호출 지점이 참조 된 변수가 뒤 따르는 경우, 그렇지 않으면 범위가 나지 않고 스토리지가 재활용되었습니다.

예를 들어이 JavaScript를 고려하십시오.

function makeClosure() {
  var x = "Remember me!";
  return function() {
    return "x='" + x + "'";
  }
}

// console.log(x); 
// The above is an error; x is undefined
var f = makeClosure();
console.log(f());
// The above outputs a string that includes x as it existed when f was created.

변수 x 기능의 본문 내에서만 정의됩니다 makeClosure; 그 정의를 제외하고는 존재하지 않습니다. 우리가 전화 한 후 makeClosure,, x 내부는 사라져야한다고 선언했다. 그리고 그것은 대부분의 코드의 관점에서 볼 때입니다. 그러나 기능은 다시 반환되었습니다 makeClosure 중간에 선언되었습니다 x 존재 했으므로 나중에 호출 할 때 여전히 액세스 할 수 있습니다. 그것은 진정한 폐쇄입니다.

범위를 보존하지 않기 때문에 클로저가 아닌 기능 값을 가질 수 있습니다. 부분 폐쇄를 가질 수도 있습니다. PHP의 함수 값은 값이 생성 된 시점에 나열되어야하는 특정 변수 만 보존합니다.

전체 기능을 전혀 나타내지 않는 호출 가능한 코드 값을 가질 수도 있습니다. Smalltalk은 이러한 "블록 클로저"라고 부르며 Ruby는 그들을 "Procs"라고 부르지 만 많은 Rubyists는 단지 그들을 "블록"이라고 부릅니다. 왜냐하면 그들은 {...} 또는 do...end 통사론. Lambdas (또는 "기능 폐쇄")와 구별되는 것은 새로운 통화 레벨을 도입하지 않는다는 것입니다. 블록 클로저 본문의 코드가 호출되는 경우 return, 그것은 외부 함수/방법에서 반환됩니다. 블록 클로저는 블록 자체뿐만 아니라 내부에 존재합니다.

그 행동은 RD Tennent가 "서신 원칙"에 표시 한 내용을 보존하는 데 중요합니다. 이는 코드를 본문에 해당 코드를 포함하는 인라인 함수로 바꾸고 즉시 호출 할 수 있어야한다고 명시합니다. 예를 들어, JavaScript에서는 다음을 대체 할 수 있습니다.

x=2
console.log(x)

이것으로 :

(function(){x = 2;})();
console.log(x)

이 예는 그다지 흥미롭지는 않지만 프로그램의 행동에 영향을 미치지 않고 이러한 종류의 변형을 수행하는 능력은 기능적 리팩토링에 중요한 역할을합니다. 하지만 람다와 함께, 당신이 내장하자마자 return 진술, 원칙은 더 이상 유지되지 않습니다.

function foo1() {
  if (1) {
    return;
  }
  console.log("foo1: This should never run.")
}
foo1()
function foo2() {
  if (1) {
    (function() { return; })();
  }
  console.log("foo2: This should never run.")
}
foo2()

두 번째 함수는 첫 번째 기능과 다릅니다. 그만큼 console.log 이기 때문에 실행됩니다 return 익명 기능에서만 돌아옵니다 foo2. 이것은 서신 원칙을 깨뜨립니다.

그렇기 때문에 루비는 Procs와 Lambdas를 모두 가지고있는 이유입니다. Procs와 Lambdas는 모두 클래스의 대상입니다 Proc, 그러나 위에서 지적한대로 다르게 행동합니다. return 람다의 몸에서 돌아 오지만 Proc를 둘러싼 방법에서 돌아옵니다.

def test
  p = proc do return 1 end
  l = lambda do return 1 end
  r = l[]
  puts "Called l, got #{r}, still here."
  r = p[]
  puts "Called p, got #{r}, still here?"
end

test 메소드는 두 번째로 가지 않습니다 puts, 의 호출이기 때문에 p 원인이됩니다 test 즉시 반환하려면 (반환 값이 1 인). JavaScript에 블록 클로저가 있으면 같은 일을 할 수 있지만 (추가 할 제안이 있지만) 그렇지 않습니다.

시끄럽고 수염이있는 것은 클로저와 블록에 대해 다음과 같이 말할 수 있습니다.

http://martinfowler.com/bliki/closure.html

어느 시점에서 그는 폐쇄는 방법에 대한 인수로 전달 될 수있는 블록이라고 말합니다.

사용하는 용어가 가장 일반적으로 사용됩니다 함께 요즘 루비에서는 구조물이 이전에 Algol, Smalltalk 및 Scheme에 나타났습니다. 루비 표준이 있다면 인용 할 것입니다.

나는 당신의 정확한 질문에 대답 할 수 있을지 확신하지 못하지만 설명 할 수 있습니다. 당신이 이미 이것을 알고 있다면 사과드립니다 ...

def f &x
  yield
  x
end

def g
  y = "block"
  t = f { p "I'm a #{y}" }
  y = "closure"
  t
end

t = g
t.call

그리고...

$ ruby exam.rb
"I'm a block"
"I'm a closure"
$ 

그래서 블록입니다 메소드 호출에 첨부 된 익명 기능과 같은 코드 시퀀스. 루비 API 전체에 사용됩니다. 익명의 함수를 쉽게 만들 수있게되면 모든 종류의 것들에 유용합니다.

그러나 그 후에 주목하십시오 f 그러면 돌아옵니다 g 반품, 우리는 블록을 반환하여 블록을 유지했습니다. f (처럼 x) 그리고 나서 g (처럼 t). 이제 우리는 블록을 두 번째로 부릅니다. 다시, 그 점에 유의하십시오 g() 돌아왔다. 그러나 블록은 더 이상 존재하지 않는 함수 인스턴스 (및 범위)의 로컬 변수를 나타냅니다! 그리고 그것은 새로운 가치를 얻습니다 y?!

그래서 폐쇄입니다 어휘 범위에 걸쳐 닫힌 함수와 같은 객체. 기능 호출 인스턴스의 로컬 변수에 매우 유용한 DO-IT-With-A-Stack 모델을 파괴하기 때문에 구현하기가 매우 어렵습니다.


1. 루비는 다양한 풍미의 클로저와 같은 기능 객체를 가지고 있습니다. 이것은 그들 중 하나 일뿐입니다.

5

그게 an입니다 정수.

int WorkDaysInaweek = 5

그게 an입니다 정수 변수 그리고 그것은 다른 것으로 설정 될 수 있습니다 정수. (상황이 해당 값을 수정하는 것을 방해하는 경우 끊임없는.)

반면 위의 숫자는 블록 그리고 폐쇄 관심 알고리즘. 의 구별 블록 그리고 폐쇄, 각각은 또한 상기와 동일하다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top