Чому більшість мов програмування мають спеціальні ключові слова або синтаксис для оголошення функцій? [зачинено]


39

Більшість мов програмування (як динамічно, так і статично набрані мови) мають спеціальне ключове слово та / або синтаксис, який виглядає набагато інакше, ніж декларування змінних для декларування функцій. Я бачу функції так само, як декларування іншого названого об'єкта:

Наприклад в Python:

x = 2
y = addOne(x)
def addOne(number): 
  return number + 1

Чому ні:

x = 2
y = addOne(x)
addOne = (number) => 
  return number + 1

Аналогічно на такій мові, як Java:

int x = 2;
int y = addOne(x);

int addOne(int x) {
  return x + 1;
}

Чому ні:

int x = 2;
int y = addOne(x);
(int => int) addOne = (x) => {
  return x + 1;
}

Цей синтаксис здається більш природним способом декларування чогось (будь то функція чи змінна) та одним менш ключовим словом, як-от defабо functionв деяких мовах. І, IMO, він більш послідовний (я шукаю там же, щоб зрозуміти тип змінної чи функції) і, ймовірно, робить парсер / граматику трохи простіше написати.

Я знаю, що дуже мало мов використовує цю ідею (CoffeeScript, Haskell), але більшість поширених мов мають спеціальний синтаксис функцій (Java, C ++, Python, JavaScript, C #, PHP, Ruby).

Навіть у Scala, яка підтримує обидва способи (і має умовивід типу), частіше писати:

def addOne(x: Int) = x + 1

Замість:

val addOne = (x: Int) => x + 1

IMO, як мінімум у Scala, це, мабуть, найбільш зрозуміла версія, але ця ідіома рідко дотримується:

val x: Int = 1
val y: Int = addOne(x)
val addOne: (Int => Int) = x => x + 1

Я працюю над моєю власною іграшкою, і мені цікаво, чи є якісь підводні камені, якщо я мою свою мову таким чином і чи є якісь історичні чи технічні причини?


9
Причина, ймовірно, історична. Хто перший це робив, той робив це так, а всі інші копіювали. Але я сумніваюся, що ми можемо знати точно.

29
Я думаю, що це тому, що функція чи метод просто не є лише іншим названим об'єктом . У функціональних мовах вони є (ви можете передавати їх і т. Д.), Але в інших мовах (наприклад, Java) функція або метод щось зовсім не відрізняється від простої змінної і не може розглядатися як така (я визнаю, вид Java 8 слабшає це твердження), тому має сенс визначати функції / методи по-різному, оскільки вони ведуть себе по- різному.
11684 р.

15
Я не погоджуюся з тим, що ваша пропозиція є більш природним способом декларування функцій. Мені справді не подобається синтаксис Coffeescript, і частина цього стосується синтаксису оголошення його функції. Справа в тому, що якщо він не зламався, не виправте це. Написання 'def' або 'function' не є великою справою і є набагато більш очевидним поглядом порівняно з деякими вигадливими символами Perl, подібними до того, що з немислими або стомленими очима легко можна помилитися з чимось іншим. Цілком особиста примітка, я також думаю, що запропонований вами синтаксис у прикладах виглядає набагато потворніше, ніж у поточному синтаксисі.
Рой

22
Як "=>" не є "спеціальним ключовим словом чи синтаксисом для оголошення функції"?
TML

11
Я не знаю про вас, але для мене (int => int) addOne = (x) => {набагато більше "особливого" та "складного", ніж int addOne(int) {...
Богдан Олександру,

Відповіді:


48

Я думаю, що причина полягає в тому, що більшість популярних мов походять або під впливом сімейства мов C на відміну від функціональних мов та їх кореня, лямбдального числення.

І в цих мовах функції не просто інше значення:

  • У C ++, C # та Java ви можете перевантажувати функції: ви можете мати дві функції з тим самим іменем, але різною підписом.
  • У C, C ++, C # та Java ви можете мати значення, які представляють функції, але покажчики функцій, функтори, делегати та функціональні інтерфейси всі відрізняються від самих функцій. Частина причини полягає в тому, що більшість із них насправді не є лише функціями, вони є функцією разом із деяким (змінним) станом.
  • Змінні мінливі за замовчуванням (ви повинні використовувати const, readonlyабо finalзаборонити мутації), але функції не можуть бути змінені.
  • З більш технічної точки зору, код (який складається з функцій) і дані є окремими. Зазвичай вони займають різні частини пам'яті, і до них звертаються по-різному: код завантажується один раз, а потім лише виконується (але не читається і не записується), тоді як дані часто постійно розподіляються і розміщуються і записуються і читаються, але ніколи не виконуються.

    А оскільки С мався на увазі "близький до металу", то це розрізнення має сенс відображати і в синтаксисі мови.

  • Підхід "функція - це лише цінність", який складає основу функціонального програмування, набув тяги в загальних мовах лише порівняно недавно, про що свідчить пізнє введення лямбда в C ++, C # та Java (2011, 2007, 2014).


12
C # мав анонімні функції - це просто лямбда без виводу типу та незграбного синтаксису - з 2005 року.
Ерік Ліпперт,

2
"З більш технічної точки зору, код (який складається з функцій) і дані є окремими" - деякі мови, найбільш свідомо LISP, не роблять цього розділення і насправді не трактують код і дані занадто інакше. (LISPs - найвідоміший приклад, але є маса інших мов, таких як REBOL, які це роблять)
Benjamin Gruenbaum,

1
@BenjaminGruenbaum Я говорив про складений код у пам'яті, а не про рівень мови.
svick

C має функціональні покажчики, які, принаймні незначно, можна розглядати як лише інше значення. Небезпечне значення, щоб возитися, напевно, але чужі речі трапилися.
Патрік Х'юз

@PatrickHughes Так, я згадую їх у своєму другому пункті. Але покажчики функцій сильно відрізняються від функцій.
svick

59

Це тому, що людині важливо усвідомити, що функції - це не просто "інша названа сутність". Іноді має сенс маніпулювати ними як такими, але вони все одно здатні розпізнатись з першого погляду.

Насправді не важливо, що комп'ютер думає про синтаксис, оскільки незрозумілий набір символів чудово розуміє машина, але це було б майже неможливо для розуміння та підтримки.

Це дійсно та сама причина, чому ми маємо час і для циклів, перемикаємось, а якщо інакше, і т. Д., Навіть незважаючи на те, що всі вони зрештою зводяться до інструкцій порівняння та стрибків. Причина полягає в тому, що він є для блага, щоб люди підтримували і розуміли код.

Наявність ваших функцій як "іншої названої сутності", як ви пропонуєте, зробить ваш код важче бачити, а отже, важче зрозуміти.


12
Я не погоджуюсь, що трактування функцій як названих сутностей обов'язково ускладнює розуміння коду. Це майже напевно вірно для будь-якого коду, який дотримується процедурної парадигми, але може бути неправдивим для коду, який слідує за функціональною парадигмою.
Кайл Странд

29
"Це дійсно та сама причина, чому ми маємо час і для циклів, перемикаємось, а якщо інакше, і т. Д., Хоча всі вони в кінцевому підсумку зводяться до інструкцій порівняння та переходу. " +1 до цього. Якби всі програмісти були зручні з машинною мовою, нам би не знадобилися всі ці вигадливі мови програмування (високий або низький рівень). Але правда така: кожен має різний рівень комфорту щодо того, наскільки близько до машини вони хочуть написати свій код. Як тільки ви знайдете свій рівень, вам просто доведеться дотримуватися наданого вам синтаксису (або написати власні специфікації мови та компілятор, якщо вас справді турбує).
Хокі

12
+1. Більш стислий варіант може бути "Чому всі природні мови відрізняють іменники від дієслів?"
msw

2
"незрозуміла плівка символів - це чудово, що машина може інтерпретувати, але це було б майже неможливо, щоб люди зрозуміли і підтримували". Яка необґрунтована кваліфікація для такої скромної синтаксичної зміни, як запропоновано у питанні. Один швидко адаптується до синтаксису. Ця пропозиція є набагато менш радикальним відхиленням від конвенції, ніж синтаксис виклику методу OO для об'єкта. Метод (args) був свого часу, але останній не виявився майже неможливим для людини зрозуміти та підтримувати. Незважаючи на те, що у більшості мов ОО не слід вважати методи збереженими в екземплярах класу.
Марк ван Левен

4
@MarcvanLeeuwen. Ваш коментар правдивий і має сенс, але деяка плутанина спровокована тим, як редагується оригінальний пост. Насправді є два питання: (i) Чому саме так? та (ii) Чому б не таким чином? . Відповідь на whatsisnameце стосувалася більше першого питання (та попередження про деяку небезпеку усунення цих помилок), тоді як ваш коментар більше стосується другої частини питання. Дійсно змінити цей синтаксис можна (і як ви описали, це було зроблено вже багато разів ...), але він не підійде всім (як і oop , не подобається всім.
Hoki

10

Вам може бути цікаво дізнатися, що, ще в доісторичні часи, мова під назвою ALGOL 68 використовувала синтаксис, близький до запропонованого вами. Визнаючи, що ідентифікатори функції прив’язані до значень так само, як і інші ідентифікатори, ви могли б цією мовою оголосити функцію (константу) за допомогою синтаксису

name -type name = ( список параметрів ) type-type : body ;

Конкретно ваш приклад прочитав би

PROC (INT)INT add one = (INT n) INT: n+1;

Визнаючи надмірність у тому, що початковий тип може бути зчитаний з RHS декларації, і будучи типом функції завжди починається з PROCцього, це може (і, як правило, буде) укладено

PROC add one = (INT n) INT: n+1;

але зауважте, що =все ще знаходиться перед списком параметрів. Також зауважте, що якщо ви хотіли змінну функції (якій пізніше можна призначити інше значення того ж типу функції), її =слід замінити :=, надавши будь-яку з

PROC (INT)INT func var := (INT n) INT: n+1;
PROC func var := (INT n) INT: n+1;

Однак у цьому випадку обидві форми насправді є скороченнями; оскільки ідентифікатор func varпозначає посилання на локально генеровану функцію, буде повністю розширена форма

REF PROC (INT)INT func var = LOC PROC (INT)INT := (INT n) INT: n+1;

До цієї особливої ​​синтаксичної форми легко звикнути, але вона, очевидно, не мала великої кількості наступних мов програмування. Навіть функціональні мови програмування, такі як Haskell, віддають перевагу стилю f n = n+1з = дотриманням списку параметрів. Я здогадуюсь, причина в основному психологічна; зрештою, навіть математики часто не віддають перевагу, як я, f = nn + 1 над f ( n ) = n + 1.

До речі, вищезгадане обговорення виділяє одну важливу різницю між змінними та функціями: визначення функцій зазвичай пов'язують ім'я з одним конкретним значенням функції, яке не можна згодом змінити, тоді як визначення змінних зазвичай вводять ідентифікатор з початковим значенням, але таке, що може змінитися пізніше. (Це не абсолютне правило; змінні функції та постійні нефункціональні константи трапляються у більшості мов.) Більше того, у мовах, що складені, значення, пов'язане у визначенні функції, зазвичай є постійною часом компіляції, так що виклики функції можуть бути складений за допомогою фіксованої адреси в коді. У C / C ++ це навіть вимога; еквівалент ALGOL 68

PROC (REAL) REAL f = IF mood=sunny THEN sin ELSE cos FI;

не можна записати на C ++ без введення покажчика функції. Цей вид специфічних обмежень виправдовує використання іншого синтаксису для визначень функцій. Але вони залежать від мовної семантики, і обґрунтування стосується не всіх мов.


1
"Математики не віддають перевагу f = nn + 1 над f ( n ) = n + 1" ... Не кажучи вже про фізиків, які люблять писати лише f = n + 1 ...
leftaround about Oko

1
@leftaroundabout це тому, що ⟼ боляче писати. Чесно.
П’єр Арло

8

Ви згадали Яву та Скалу як приклади. Однак ви не помітили важливого факту: це не функції, це методи. Методи та функції принципово різні. Функції - це об'єкти, методи належать до об'єктів.

У Scala, яка має і функції, і методи, існують такі відмінності між методами та функціями:

  • методи можуть бути загальними, функції не можуть
  • Методи можуть мати не один, ані багато списків параметрів, функції завжди мають точно один список параметрів
  • методи можуть мати неявний список параметрів, функції не можуть
  • методи можуть мати необов'язкові параметри з аргументами за замовчуванням, функції не можуть
  • методи можуть мати повторні параметри, функції не можуть
  • методи можуть мати параметри назви, функції не можуть
  • методи можна викликати названими аргументами, функції не можуть
  • функції - об'єкти, методи - ні

Отже, запропонована вами заміна просто не працює, принаймні для цих випадків.


2
"Функції - об'єкти, методи належать до об'єктів." Це стосується всіх мов (наприклад, C ++)?
svick

9
"Методи можуть мати параметри назви, функції не можуть" - це не принципова різниця між методами та функціями, це лише химерність Scala. Те саме з більшістю (усі?) Інших.
користувач253751

1
Методи принципово просто особливий вид функцій. -1. Зауважте, що Java (і за розширенням Scala) не має жодних інших функцій. Це "функції" - це об'єкти з одним методом (загалом функції можуть бути не об'єктами або навіть значеннями першого класу; чи вони залежать від мови).
Ян Худек,

@JanHudec: семантично Java має і функції, і методи; вона використовує термінологію "статичні методи" при посиланні на функції, але така термінологія не стирає смислового розрізнення.
supercat

3

Причини, про які я можу подумати:

  • Компілятору простіше знати, що ми декларуємо.
  • Нам важливо знати (тривіально), чи це функція, чи змінна. Функції, як правило, є чорними полями, і ми не переймаємось їх внутрішньою реалізацією. Мені не подобається висновок про типи повернення в Scala, тому що я вважаю, що простіше використовувати функцію, що має тип повернення: це часто єдина надана документація.
  • І найголовніше - це наступна стратегія натовпу, яка використовується при розробці мов програмування. C ++ створений для крадіжок програмістів на C, а Java розроблялася таким чином, що не лякає програмістів на C ++, а C # для залучення Java-програмістів. Навіть C #, який, на мою думку, є дуже сучасною мовою з дивовижною командою за ним, скопіював деякі помилки з Java або навіть з C.

2
"… І C # для залучення Java-програмістів" - це сумнівно, C # набагато більше схожий на C ++, ніж на Java. а іноді схоже на те, що це було зроблено навмисно несумісним з Java (ніяких символів, жодних внутрішніх класів, ніякої коваріації типу повернення…)
Sarge Borsch,

1
@SargeBorsch Я не думаю, що це було навмисно зроблено несумісним з Java, я впевнений, що команда C # просто намагалася зробити це правильно або зробити це краще, проте ви хочете, щоб на це поглянути. Компанія Microsoft вже написала власні Java & JVM і подала позов до суду. Тож команда C #, ймовірно, дуже мотивувала затемнення Java. Це, безумовно, несумісне, і краще для цього. Java почалася з деякими основними обмеженнями, і я радий, що команда C # вибрала, наприклад, робити дженеріки по-різному (видно в системі типів, а не тільки в цукрі).
codenheim

2

Якщо вирішити питання, якщо вам не цікаво намагатися редагувати вихідний код на машині, яка надзвичайно обмежена оперативною пам’яттю, або звести до мінімуму час для його зчитування з дискети, що не так з використанням ключових слів?

Звичайно, краще читати, x=y+zніж це store the value of y plus z into x, але це не означає, що знаки пунктуації за своєю суттю "кращі", ніж ключові слова. Якщо змінні i, jі kце Integer, і xце Real, розглянемо наступні рядки в Pascal:

k := i div j;
x := i/j;

Перший рядок буде виконувати обрізання цілого поділу, а другий - ділення реального числа. Відмінність може бути зроблена непогано, оскільки Паскаль використовує divяк свій оператор ділення обрізання цілих чисел, а не намагається використовувати розділовий знак, який вже має інше призначення (поділ реального числа).

Хоча є кілька контекстів, в яких може бути корисним визначення функції функції лаконічним (наприклад, лямбда, який використовується як частина іншого виразу), функції, як правило, повинні виділятися і легко візуально розпізнаватися як функції. Хоча це може зробити розрізнення набагато більш тонким і не використовувати нічого, крім розділових знаків, який би був сенс? Висловлювання Function Foo(A,B: Integer; C: Real): Stringдає зрозуміти, як називається функція, які параметри її очікують і що вона повертає. Може, можна було скоротити його на шість чи сім символів, замінивши Functionдеякі знаки пунктуації, але що було б отримано?

Ще одне, що слід зазначити, є те, що в більшості фреймворків є принципова відмінність між декларацією, яка завжди пов'язує ім'я або з певним методом, або з певним віртуальним прив'язкою, і тим, що створює змінну, яка спочатку ідентифікує певний метод або прив'язку, але може бути змінено під час виконання для виявлення іншого. Оскільки це дуже семантично дуже різні поняття в більшості процедурних рамок, то є сенс, що вони повинні мати різний синтаксис.


3
Я не думаю, що це питання стосується стислість. Тим більше, що, наприклад void f() {}, насправді коротший, ніж еквівалент лямбда у C ++ ( auto f = [](){};), C # ( Action f = () => {};) та Java ( Runnable f = () -> {};). Лаконічність лямбдахів випливає з виводу типу і пропущення return, але я не думаю, що це пов'язано з тим, що задаються ці питання.
svick

2

Ну, причина може бути в тому, що ці мови є недостатньо функціональними, так би мовити. Іншими словами, ви досить рідко визначаєте функції. Таким чином, використання зайвого ключового слова є прийнятним.

Мовами спадщини ML або Miranda, OTOH, ви визначаєте функції більшість часу. Наприклад, подивіться на якийсь код Haskell. Це буквально переважно послідовність визначень функцій, багато з них мають локальні функції та локальні функції цих локальних функцій. Отже, цікаве ключове слово в Haskell було б помилкою настільки ж великим, як вимагати заяви про відстеження обов'язковою мовою, щоб почати з присвоєння . Призначення причин - це, мабуть, єдине найчастіше твердження.


1

Особисто я не бачу фатальної вади у вашій ідеї; ви можете виявити, що це складніше, ніж ви очікували, щоб висловити певні речі, використовуючи новий синтаксис, та / або ви можете виявити, що вам потрібно переглянути його (додавання різних спеціальних справ та інших функцій тощо), але я сумніваюся, що ви знайдете себе потрібно повністю відмовитися від ідеї.

Запропонований вами синтаксис виглядає більш-менш схожим на варіант деяких стилів позначень, які іноді використовуються для вираження функцій або типів функцій у математиці. Це означає, що, як і всі граматики, це, мабуть, сподобається деяким програмістам, ніж іншим. (Як математику, мені трапляється подобається.)

Тим НЕ менше, слід зазначити , що в більшості мов, то def-стиль синтаксис (тобто традиційного синтаксису) робить поведінка відрізняється від стандартного розподілу змінного.

  • У сім'ї Cта C++сім'ї функції, як правило, не трактуються як "об'єкти", тобто шматки набраних даних, які потрібно скопіювати та помістити в стек та ін. (Так, ви можете мати покажчики функцій, але ті все ще вказують на виконуваний код, а не на "дані" в типовому сенсі.)
  • У більшості мов OO існує спеціальна обробка методів (тобто функцій членів); тобто вони не просто функції, задекларовані в межах визначення класу. Найголовніша відмінність полягає в тому, що об'єкт, щодо якого викликається метод, зазвичай передається методу як неявний перший параметр. Python робить це явним із self(що, до речі, насправді не є ключовим словом; ви можете зробити будь-який дійсний ідентифікатор першим аргументом методу).

Вам потрібно врахувати, чи точно ваш (і, сподіваємось, інтуїтивно зрозумілий) ваш новий синтаксис відображає те, що насправді робить компілятор чи інтерпретатор. Це може допомогти прочитати, скажімо, про різницю між лямбдами та методами у Рубі; це дасть вам уявлення про те, як парадигма ваших функцій - це просто дані відрізняється від типової парадигми OO / процедури.


1

Для деяких мов функції не є значеннями. Такою мовою це сказати

val f = << i : int  ... >> ;

- це визначення функції, тоді як

val a = 1 ;

оголошує константу, заплутаний, тому що ви використовуєте один синтаксис для позначення двох речей.

Інші мови, такі як ML, Haskell та Scheme, розглядають функції як значення 1-го класу, але надають користувачеві спеціальний синтаксис для декларування функцій, що оцінюються константами. * Вони застосовують правило, що "використання скорочує форму". Тобто, якщо конструкція є і загальною, і багатослівною, ви повинні дати користувачеві стенограму. Неелегантно давати користувачеві два різні синтаксиси, які означають абсолютно одне й те саме; іноді елегантності слід принести в жертву корисності.

Якщо у вашій мові функції 1-го класу, то чому б не спробувати знайти синтаксис, який є досить стислим, щоб ви не спокусилися знайти синтаксичний цукор?

- Редагувати -

Ще одне питання, про яке ніхто ще не піднявся, - це рекурсія. Якщо ви дозволяєте

{ 
    val f = << i : int ... g(i-1) ... >> ;
    val g = << j : int ... f(i-1) ... >> ;
    f(x)
}

і ти дозволяєш

{
    val a = 42 ;
    val b = a + 1 ;
    a
} ,

чи випливає, що ви повинні дозволити

{
    val a = b + 1 ; 
    val b = a - 1 ;
    a
} ?

На ледачій мові (як Haskell) тут немає жодної проблеми. У мові, де фактично немає статичних перевірок (як LISP), тут немає жодної проблеми. Але статично перевіреною прагнею мови ви повинні бути обережними, як визначаються правила статичної перевірки, якщо ви хочете дозволити перші два і заборонити останню.

- Кінець редагування -

* Можна стверджувати, що Haskell не належить до цього списку. Він надає два способи оголошення функції, але обидва в певному сенсі є узагальненнями синтаксису для декларування констант інших типів


0

Це може бути корисним для динамічних мов, де тип не такий важливий, але він не начитається на статичних мовах, де завжди потрібно знати тип змінної. Крім того, в об'єктно-орієнтованих мовах досить важливо знати тип змінної, щоб знати, які операції вона підтримує.

У вашому випадку функцією з 4 змінними буде:

(int, long, double, String => int) addOne = (x, y, z, s) => {
  return x + 1;
}

Коли я дивлюся на заголовок функції і бачу (x, y, z, s), але я не знаю типів цих змінних. Якщо я хочу знати, тип zякого є третім параметром, я повинен переглянути початок функції і почати рахувати 1, 2, 3, а потім побачити, що це тип double. По-колишньому я дивлюсь прямо і бачу double z.


3
Звичайно, є така чудова річ під назвою типу умовиводу, яка дозволяє написати щось на зразок var addOne = (int x, long y, double z, String s) => { x + 1 }неморонічної статично набраної мови на ваш вибір (приклади: C #, C ++, Scala). Навіть інакше дуже обмежений локальний висновок, який використовується C #, цілком достатній для цього. Тож ця відповідь є лише критикою конкретного синтаксису, який, в першу чергу, сумнівний і фактично ніде не використовується (хоча синтаксис Haskell має дуже схожу проблему).
амон

4
@amon Його відповідь може критикувати синтаксис, але він також вказує на те, що призначений синтаксис у питанні може бути не "природним" для всіх.

1
@amon Корисність виводу типу - це не чудова річ для всіх. Якщо ви читаєте код частіше, ніж ви пишете код, то вводити висновок погано, оскільки вам доведеться робити висновок у голові під час читання коду; і набагато швидше читати тип, ніж насправді думати про те, який тип використовується.
m3th0dman

1
Критика здається мені справедливою. Для Java, ОП, здається, думає, що [введення, вихід, ім'я, введення] є більш простою / чіткішою функцією, ніж просто [вихід, ім'я, введення]? Як зазначає @ m3th0dman, при більш тривалих підписах "чистіший" підхід ОП стає дуже завзятим.
Майкл

0

Існує дуже проста причина такого розмежування у більшості мов: є необхідність розрізняти оцінку та декларацію . Ваш приклад хороший: чому не подобаються змінні? Ну, вирази змінних негайно оцінюються.

У Haskell є спеціальна модель, де немає різниці між оцінкою та декларацією, тому немає необхідності в спеціальному ключовому слові.


2
Але деякі синтаксиси лямбда-функцій також вирішують це, то чому б не використати це?
svick

0

Функції оголошуються по-різному від літералів, об'єктів тощо у більшості мов, оскільки вони використовуються по-різному, налагоджуються по-різному та створюють різні потенційні джерела помилок.

Якщо посилання динамічного об'єкта або об'єкт, що змінюється, передається функції, функція може змінювати значення об'єкта під час його запуску. Цей вид побічного ефекту може ускладнити простеження того, що виконуватиме функція, якщо вона вкладена в складний вираз, і це поширена проблема в таких мовах, як C ++ та Java.

Розглянемо налагодження якогось модуля ядра в Java, де кожен об’єкт має операцію toString (). Хоча може очікуватися, що метод toString () повинен відновити об'єкт, можливо, йому доведеться розібрати і зібрати об'єкт, щоб перевести його значення в об'єкт String. Якщо ви намагаєтеся налагодити методи, які ToString () буде викликати (у сценарії з підключенням і шаблоном) виконувати свою роботу, і випадково виділити об'єкт у вікні змінних більшості IDE, це може зламати налагоджувач. Це тому, що IDE намагатиметься toString () об'єкт, який викликає той самий код, який ви знаходитесь в процесі налагодження. Жодне примітивне значення ніколи не лає так, оскільки семантичне значення примітивних значень визначається мовою, а не програмістом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.