Вопрос

Я обнаружил, что многие люди используют эти слова закрытие и блок взаимозаменяемо.Большинство из этих людей не могут объяснить, о чем они говорят.

Некоторые Java-программисты (даже из действительно дорогих консалтинговых компаний) говорят об анонимных внутренних классах как о "блоках" и "замыканиях", но я знаю, что это неправда.(Вы не можете передавать изменяемые переменные из области действия метода, в котором они определены ...)

Я ищу:

  • точная компьютерная наука определение блока
  • точная компьютерная наука определение замыкания
  • и разъяснение разницы между этими двумя.

Я бы очень хотел увидеть ссылки, статьи или книгу ссылки на них, пожалуйста.

Это было полезно?

Решение

В то время как a блок это просто фрагмент кода, который может быть составлен с помощью операторов и деклараций, но ничего больше, a закрытие это реальный объект первого класса, реальная переменная, которая имеет блок в качестве своего значения.

Основное отличие заключается в том, что блок просто группирует инструкции вместе (например, тело в то время как оператор), в то время как замыкание - это переменная, содержащая некоторый код, который может быть выполнен.

Если у вас есть замыкание, обычно вы можете передать его в качестве параметра функциям, очистить и отменить его, и, в основном, вызвать его!

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

Конечно, замыкания более мощные, они являются переменными и могут использоваться для определения пользовательского поведения объектов (в то время как обычно вам приходилось использовать интерфейсы или другие подходы ООП в программировании).

Вы можете придумать закрытие как функция, которая содержит то, что эта функция делает внутри себя.

Блоки полезны, потому что они позволяют определять область действия переменных.Обычно, когда вы определяете переменную внутри области видимости, вы можете переопределить внешние определения без каких-либо проблем, и новые определения будут существовать только во время выполнения block .

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
}

Замыкание связано с анонимными функциями или классами - анонимным объектом (function), фрагментом кода, который привязан к среде (с ее переменными).

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, в котором блок и закрытие обрабатываются аналогично, поскольку то, что Ruby вызывает block является закрытие:

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

Там each-методу передается функция замыкания (принимающая параметр x), которая вызывается блок в Ruby.

Здесь много путаницы, потому что есть термины с несколькими определениями и множество разных вещей, которые объединяются просто потому, что они обычно встречаются вместе.

Во-первых, у нас есть "блок".Это всего лишь лексический фрагмент кода, который создает единицу - например, тело цикла.Если язык действительно имеет область действия блока, то могут быть определены переменные, которые существуют только в пределах этого фрагмента кода.

Во-вторых, у нас есть вызываемый код в качестве типа значения.В функциональных языках это значения функций, иногда называемые "funs", "анонимные функции" (потому что функция находится в значении, а не в имени, которому она присвоена;вам не нужно имя, чтобы вызывать их), или "лямбда-выражения" (от оператора, используемого для их создания в лямбда-исчислении Черча).Их можно назвать "замыканиями", но они не являются автоматически истинными замыканиями;чтобы соответствовать требованиям, они должны инкапсулировать ("закрывать") лексическую область видимости, окружающую их создание, то есть переменные, определенные вне области видимости самой функции, но в пределах области видимости ее определения, по-прежнему доступны всякий раз, когда вызывается функция, даже если точка вызова находится после того, как указанная переменная в противном случае вышла бы из области видимости и ее хранилище было бы переработано.

Например, рассмотрим этот 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 называет их "процессами", хотя многие разработчики Ruby называют их просто "блоками", потому что они являются овеществленной версией того, что создано {...} или do...end синтаксис.Что отличает их от лямбд (или "замыканий функций"), так это то, что они не вводят новый уровень вызова. Если код в теле закрытия блока вызывает return, он возвращает из внешней функции / метода, внутри которого существует закрытие блока, а не только сам блок.

Такое поведение имеет решающее значение для сохранения того, что R.D.Теннент назвал "принципом соответствия", который гласит, что вы должны иметь возможность заменить любой код встроенной функцией, содержащей этот код в теле и вызываемой немедленно.Например, в 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.Это нарушает принцип соответствия.

Вот почему в Ruby есть как procs, так и lambdas, хотя это различие является постоянным источником путаницы для новичков.Как procs, так и лямбды являются объектами класса Proc, но они ведут себя по-разному, как указано выше:a 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

В какой-то момент он говорит, что замыкание - это блок, который может быть передан в качестве аргумента методу.

Термины, которые вы используете, являются наиболее часто используемыми вместе в наши дни на Ruby, хотя конструкции ранее появлялись в Algol, Smalltalk и Scheme.Я бы процитировал стандарт Ruby, если бы он существовал.

Я не уверен, что смогу ответить на ваш точный вопрос, но я могу проиллюстрировать.Приношу свои извинения, если вы это уже знаете...

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"
$ 

Таким образом, блок - это анонимная последовательность кода, подобная функции, прикрепленная к вызову метода.Он используется во всем Ruby API.Когда вы достаточно упрощаете создание анонимных функций, оказывается, что они полезны для самых разных целей.

Но обратите внимание, что после f возвращается, затем g возвращает, мы удержали блок, вернув его из f (как x) а затем из g (как t).Теперь мы вызываем блок во второй раз.Опять же, обратите внимание, что g() вернулся.Но блок ссылается на локальную переменную в экземпляре функции (и области видимости), которая больше не существует ?!И он получает новое значение y?!

Таким образом, закрытие - это функциональноподобный объект, который закрыт по своей лексической области.Их довольно сложно реализовать, потому что они разрушают модель "сделай это с помощью стека", которая так полезна для локальных переменных в экземплярах вызова функции.


1.Ruby имеет различные варианты функциональных объектов, подобных замыканию;это всего лишь один из них.

5

Это очень целое число.

Int workDaysInAWeek = 5 рабочих дней

Это очень целочисленная переменная и он может быть установлен на другой целое число.(Если обстоятельства не позволяют вам изменить это значение, оно может быть вызвано постоянный.)

Принимая во внимание, что приведенное выше касается чисел, блоки и закрытия касаются алгоритмов.Различие между блоки и закрытия, соответственно, также эквивалентно вышеописанному.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top