Функция уже определена в области — Вопрос
Пользователи СкалаДжимка
#1
Я не понимаю сообщение «функция уже определена в области».
Иногда компилятор позволяет мне определить несколько функций с одним и тем же именем, но с разными специализациями/объявлениями аргументов. Однако иногда он отмечает это как ошибку.
Может ли кто-нибудь помочь мне понять, когда это разрешено, а когда нет?
В данном случае не допускается.
Впрочем, в данном случае вроде нормально.
ждукер
#2
Хм.
(Кроме того, обычная проверка работоспособности: вы действительно пытались его скомпилировать? Никогда не верьте, что IntelliJ прав на 100% в этом вопросе. Это раздражает, но пока LSP не станет основой для всех IDE, вам нужно знать о это.)
Код, как вы показываете, кажется, должен быть в порядке, поэтому я не уверен, что здесь происходит…
jimka
#3
@jducoeur Спасибо за подсказку, да, действительно, неудачный пример включает в себя гораздо больше, поэтому мне нужно выделить лучший неудачный тестовый пример.
Кстати, в этом случае IntelliJ выдает ту же ошибку, что и scalac.
Джимка
#4
@jducoeur Вот урезанная версия, которая, кажется, все еще воспроизводит проблему. Хотя теперь код вообще работает, потому что я убрал всю логику программы.
В этом случае я все еще получаю сбивающее с толку предупреждение/ошибку компилятора о том, что у меня есть несколько определений в области видимости. Я действительно не понимаю, почему иногда это работает, а иногда нет.
gist.github.comhttps://gist.github.com/jimka2001/11dd96314687eb0112bba0e023dade9e
Metro-funny-error.scala
импорт scala.collection.immutable объект MetroFunnyError { val stationPositions = Массив ( («Настоятельницы», 308, 536), («Александр Дюма», 472, 386), («Альма Марсо», 193, 404), («Алесия», 290, 244), («Анатоль Франс», 138, 517), ("Анверс", 324, 521),

ждукер
#5
Ладно, посмотрим. Вот полностью свернутый репродуктор, так что мы можем поиграть с этим…
1 Нравится
21 марта 2019 г., 14:37
#6
О, это увлекательно. Похоже, проблема в том, что вы перегружаете определение функции внутри другой функции. Если вы удалите внешнюю функцию, вот так, ошибка исчезнет.
Видимо, это просто известное ограничение, с которым я раньше не сталкивался. Решение, данное по ссылке, является одним из возможных исправлений; другой — просто изменить имя одной из внутренних функций. (Некоторые люди в сообществе FP в целом довольно сильно выступают против перегрузок, но это один из наиболее ярких аргументов, почему это я видел…)
jimka
#7
Хорошо, мне просто нужно переименовать локальную функцию? Поскольку у нас нет типов объединения, есть ли способ переписать функцию в функцию, шаблон которой соответствует ее аргументу? Один шаблон для
и один корпус для Option[Station]
?
Кстати, спасибо за помощь. В моем положении такие вопросы действительно озадачивают. А у меня их вроде много. С моей точки зрения, я ничего не пытаюсь перегрузить? Я просто создаю функции с разной специализацией.
wrbriggs1
#8
есть ли еще способ переписать функцию в функцию, шаблон которой соответствует ее аргументу? Один шаблон для
Station
и один корпус дляOption[Station]
?
У кого-то умнее меня может быть творческое решение с использованием системы типов Scala; моя единственная мысль здесь заключается в том, что если вы настроены на другую реализацию для Option и конкретного экземпляра, вы потенциально можете написать каждую как PartialFunction и использовать orElse для их объединения.
Я довольно неравнодушен (без каламбура) к тому, чтобы просто придерживаться одного типа параметра, чтобы упростить вещи.
В вашем примере одна функция просто разворачивает Option, что кажется ненужным — возможно, вы могли бы просто сделать что-то вроде:
val startupStation = freeVertices.headOption val routings = startupStation.map(station => firstRoutings(station)) getOrElse Nil
Тогда вы можете просто отказаться от функции, которая принимает опцию.
Джимка
#9
o просто придерживаться одного типа параметра, чтобы упростить задачу.
на самом деле переименовать его очень просто. Я просто использовал то же имя, чтобы код было легче читать на месте вызова. создание двух разных имен — простой обходной путь.
ювелир
#10
Джимка:
Кстати, спасибо за помощь. В моем положении такие вопросы действительно озадачивают. А у меня их вроде много.
Нет проблем — честно говоря, вы придумали исключительно интересных вопросов для новичка в языке. И ваши инстинкты в значительной степени хороши: вы просто продвигаетесь вперед достаточно быстро, чтобы найти некоторые швы в языке. (В данном случае, тот, о котором я даже не знал…)
тарса
#11
Джимка:
Кстати, спасибо за помощь.
В моем положении такие вопросы действительно озадачивают. А у меня их вроде много. С моей точки зрения, я ничего не пытаюсь перегрузить? Я просто создаю функции с разной специализацией.
Перегрузка. См. https://en.wikipedia.org/wiki/Function_overloading
перегрузка функций или перегрузка методов — это возможность создавать несколько функций с одним и тем же именем с разными реализациями
Правила перегрузки функций
Одно и то же имя функции используется более чем для одного определения функции
Функции должны отличаться либо арностью, либо типами своих параметров
Я точно не знаю, что вы имеете в виду под специализацией, но, похоже, это просто частный случай перегрузки.
Вмечем
#12
Я думаю, проблема в том, что сигнатуры функций одинаковы, т. е. f/1. Вы можете попробовать добавить второй параметр в функцию первого уровня с нулевым значением по умолчанию или что-то в этом роде. Это даст вам f/1 и f/2, то есть разные подписи. Но переименование, безусловно, является самым чистым решением.
Джимка
№13
Еще одна причина, по которой переименование имеет смысл в моем случае, заключается в том, что мой код еще не закончен. Я все еще экспериментирую с различными способами вычисления того, что мне нужно вычислить. Я почти уверен, что окончательная производственная версия будет иметь только одну из функций или другую, но не обе.
Джимка
№14
Спасибо за ссылку на перегружает , я не знал об этой довольно распространенной терминологии; страница википедии, кажется, объясняет это довольно хорошо.
Мне это кажется забавным названием, потому что по-английски перегрузить означает вложить слишком много во что-то. Например, вы перегрузили машину слишком большим количеством багажа. В Лиспе мы называем это специализацией. То есть каждый метод специфицирует свои аргументы таким образом, который отличает его от других методов и влияет на его применимость или порядок специфичности. Мы, вероятно, (в Лиспе) использовали бы перегрузил как уничижительный, означающий, что кто-то добавил слишком много методов к своей полиморфной функции, так что теперь либо производительность, либо удобочитаемость отрицательно сказываются.
Во всяком случае, я нахожу многие концепции в Scala очень похожими на Lisp, но иногда терминология обманчива.
Джимка
№15
производитель:
вы просто продвигаетесь вперед достаточно быстро, чтобы найти некоторые швы в языке.
хе-хе-хе, а хакеры все мы любим находить любопытные случаи. Особенно приятно, что есть живое сообщество единомышленников, с которыми можно обсудить эти интересные кейсы.
Глобальные переменные — зло
Глобальные переменные — злоГлобальные переменные
Глобальная переменная — это переменная, определенная в основной программе. Говорят, что такие переменные имеют «глобальную» область видимости.
Локальная переменная — это переменная, определенная внутри функции. Говорят, что такие переменные имеют локальную область видимости.
Функции могут обращаться к глобальным переменным и изменять их.
Изменение глобальных переменных в функции считается плохой практикой программирования. Лучше отправить переменную в качестве параметра (или вернуть ее в операторе return).
Модульное программирование
Думайте о функции как о черном ящике с входами и выходами.
Ввод/вывод функции должен быть полностью определен ее функциональной сигнатурой и возвратом
заявление.
сигнатура функции имя функции и список параметров (и возвращаемая спецификация в таких языках, как java), например,
def pow(x,n) : # эта строка
подпись функции
total=1
count = 0
while count
count=count+1
return total # в Java return total #
значение также должно быть указано в сигнатуре функции
# основной
result = pow(4,2) # если модульный, мы можем предположить pow-эффекты
только результат, без других побочных эффектов
распечатать результат
При модульном программировании любой, кто читает программу, может определить эффект функция только от просмотра вызова.
При модульном программировании нет побочных эффектов , например, глобальных переменные, изменяемые в функции.
Единственным эффектом функции является возвращаемое значение и модификации
параметры списка/объекта (скаляры не могут быть изменены).
Правила области применения Python
Внутри определения функции,
если переменная прочитана , Python проверяет, была ли она определена локально. Если это не так, Python проверит, есть ли глобальная переменная с это имя. |
def func(): # прочитать пример
print x # python будет использовать глобальный x, если он существует
если в переменную записывается, для нее создается локальный слот. |
def func(): # пример записи
x=7 # глобальный не будет использоваться, даже если глобальный ‘x’ существует.
если вы хотите записать в глобальную переменную, вы должны использовать «глобальную»
заявление.![]() |
def func(): # как записать глобальную
глобальный х
x=x+1 # изменяет глобальный x
Рассмотрим следующие фрагменты программы. Какой результат?
защита f():
х=10
x=5
f()
печать x
*************
защита f():
печать х
х = 5
f()
********
защита f():
глобально x
x=10
x=5
f()
печать x
*************
защита f():
х=х+1
x=5
f()
печать x
*************
защита f():
list.append(5)
список=[1,2,3,4]
f()
распечатать список
*************
защита f():
список=[]
список.дополнение(5)
список=[1,2,3,4]
f()
распечатать список
*******************
Рабочий лист класса
1. Переписать pow и main так, чтобы они были ЗЛЫМИ, то есть НЕ МОДУЛЬНЫМИ. Просто нарисуй это
вне, не программировать его.
2. Какая из следующих функций а) работает правильно, б) использует глобальные переменные немодульным образом
# 1
def generateSecret():
secretCode=[]
i=0
while i<4:
color =
случайный.randint(0,5)
secretCode.append(colors[color])
i=i+1
# вызов основной функции
colors=[‘r’,’b’,’g’,’p’,’y’,’b’]
generateSecret()
print secretCode;
# 2
def generateSecret():
i=0
while i<4:
color =
случайный.randint(0,5)
secretCode.append(colors[color])
i=i+1
# основной вызов функции:
colors=[‘r’,’b’,’g’,’p’,’y’,’b’]
secretCode=[]
generateSecret()
print secretCode
# 3
def generateSecret():
secretCode=[]
i=0
while i<4:
color =
случайный.