ОБНОВЛЯТЬ:
Глубоко внутри общепринятого ответа находится способ исправить это; то есть переименуйте метод с main
на что-нибудь другое или переименуйте object Main
на что-нибудь другое.
Конфликт — это проблема нечувствительности к регистру в файловой системе Windows (или MacOS), где наличие одного и того же регистронезависимого значения для методов, отмеченных object
и @main
, создает проблему.
Будем надеяться, что ребята из IntelliJ Scala Plugin смогут добавить это в свою потрясающую «автоматическую систему предупреждений», чтобы никто больше не попал в эту кроличью нору Scala 3.
ОБНОВЛЕНИЕ После дальнейшего расследования... Это работает в Scastie , настоятельно предполагая, что это проблема плагина IntelliJ Scala ( Билет Jetbrains YouTrack).
После создания нового проекта Scala 3.3.3 в IntelliJ (2024.1.1) с плагином Scala (2024.1.20) мой метод «синтаксиса без скобок» Main.main
дает сбой: «Не удалось найти или загрузить основной класс org.public_domain.main» .
Должно быть, я упускаю что-то совершенно очевидное. Однако после часа возни с этим я сдаюсь. Что мне не хватает?
Вот ЕДИНСТВЕННЫЙ файл, который я создал во всем проекте, и на котором я щелкнул маленькую зеленую стрелку в левом трее метода main
, чтобы выбрать «Запустить org.public_domain.main».
package org.public_domain
object Main:
@main def main(): Unit =
println("Hello World!")
SideNote: я заметил, что IntelliJ неправильно называет org.public_domain.Main.main
методом, который я использую.
Кстати, если я закомментирую object Main:
(чего мне очень не хочется делать), всё работает нормально.
IOW, это отлично работает:
package org.public_domain
@main def main(): Unit =
println("Hello World!")
org.public_domain
вpackage org.public_domain
object Main:
@main def main(): Unit =
println("Hello World!")
то этот файл Main.scala
следует разместить по адресу /path/to/yourproject/src/main/scala/org/public_domain/Main.scala
sbt run
из корня вашего проекта распечатывает Hello World!
$ sbt run
[info] welcome to sbt 1.10.0 (Amazon.com Inc. Java 21.0.3)
[info] loading global plugins from /home/dmitin/.sbt/1.0/plugins
[info] loading project definition from /path/to/yourproject/project
[info] loading settings for project root from build.sbt ...
[info] set current project to yourproject (in build file:/path/to/yourproject/)
[info] compiling 1 Scala source to /path/to/yourproject/target/scala-3.3.3/classes ...
[warn] -- Warning: /path/to/yourproject/src/main/scala/org/public_domain/Main.scala:3:7
[warn] 3 |object Main:
[warn] | ^
[warn] |object Main differs only in case from class main in package org.public_domain. Such classes will overwrite one another on case-insensitive filesystems.
[warn] one warning found
[info] running org.public_domain.main
Hello World!
[success] Total time: 3 s, completed 18 мая 2024 г., 20:06:05
object Main differs only in case from class main in package org.public_domain. Such classes will overwrite one another on case-insensitive filesystems
. Если вы используете файловую систему без учета регистра (например, Windows или MacOS), измените имя вашего метода, напримерpackage org.public_domain
object Main:
@main def run(): Unit =
println("Hello World!")
target/scala-3.3.3/classes/org/public_domain
. Должно быть создано несколько классов (с именем объекта и именем метода, аннотированным @main
):$ cd target/scala-3.3.3/classes/org/public_domain
$ ls
main.class Main.class Main$.class main.tasty Main.tasty
(или run.class
вместо main.class
, если вы переименовали метод).
Начало работы: https://docs.scala-lang.org/getting-started/index.html
Структура каталогов Sbt: https://www.scala-sbt.org/1.x/docs/Directories.html
плагин IntelliJ Scala неправильно вызывает
org.public_domain.main
, а не правильноorg.public_domain.Main.main
Я рад, если вы решили свои проблемы, но боюсь, что вы можете неправильно истолковать свои выводы. По крайней мере, я вижу некоторую путаницу. Здесь есть несколько классов: Main.class
, Main$.class
, main.class
(или run.class
, если мы переименовали метод). Main.class
и Main$.class
представляют объект, main.class
представляет аннотированный @main
метод. Следует вызывать именно класс org.public_domain.main
(у него есть работоспособный метод public static void main(java.lang.String[])
), а не org.public_domain.Main
(у него нет main(String[])
). Вы можете увидеть методы в классах с помощью javap
:
$ cd /path/to/yourproject/target/scala-3.3.3/classes/org/public_domain/
$ ls
main.class Main.class Main$.class main.tasty Main.tasty
$ cd /path/to/yourproject/target/scala-3.3.3/classes
$ javap org.public_domain.Main
Compiled from "Main.scala"
public final class org.public_domain.Main {
public static void main();
}
$ javap org.public_domain.Main$
Compiled from "Main.scala"
public final class org.public_domain.Main$ implements java.io.Serializable {
public static final org.public_domain.Main$ MODULE$;
public static {};
public void main();
}
$ javap org.public_domain.main
Compiled from "Main.scala"
public final class org.public_domain.main {
public org.public_domain.main();
public static void main(java.lang.String[]);
}
Если вы запускаете свой код с помощью IntelliJ IDEA, а не с помощью sbt (я рекомендовал последний), вы можете настроить, что запускать, в меню Run -> Edit configurations
IntelliJ записывает точную выполняемую команду:
По умолчанию он свернут. Если щелкнуть, он расширяется. Для меня это
/media/data/jdk1.8.0_351/bin/java -javaagent:/media/data/idea-IU-241.15989.150/lib/idea_rt.jar=38299:/media/data/idea-IU-241.15989.150/bin -Dfile.encoding=UTF-8 -classpath /media/data/jdk1.8.0_351/jre/lib/charsets.jar:/media/data/jdk1.8.0_351/jre/lib/deploy.jar:/media/data/jdk1.8.0_351/jre/lib/ext/cldrdata.jar:/media/data/jdk1.8.0_351/jre/lib/ext/dnsns.jar:/media/data/jdk1.8.0_351/jre/lib/ext/jaccess.jar:/media/data/jdk1.8.0_351/jre/lib/ext/jfxrt.jar:/media/data/jdk1.8.0_351/jre/lib/ext/localedata.jar:/media/data/jdk1.8.0_351/jre/lib/ext/nashorn.jar:/media/data/jdk1.8.0_351/jre/lib/ext/sunec.jar:/media/data/jdk1.8.0_351/jre/lib/ext/sunjce_provider.jar:/media/data/jdk1.8.0_351/jre/lib/ext/sunpkcs11.jar:/media/data/jdk1.8.0_351/jre/lib/ext/zipfs.jar:/media/data/jdk1.8.0_351/jre/lib/javaws.jar:/media/data/jdk1.8.0_351/jre/lib/jce.jar:/media/data/jdk1.8.0_351/jre/lib/jfr.jar:/media/data/jdk1.8.0_351/jre/lib/jfxswt.jar:/media/data/jdk1.8.0_351/jre/lib/jsse.jar:/media/data/jdk1.8.0_351/jre/lib/management-agent.jar:/media/data/jdk1.8.0_351/jre/lib/plugin.jar:/media/data/jdk1.8.0_351/jre/lib/resources.jar:/media/data/jdk1.8.0_351/jre/lib/rt.jar:/media/data/Projects2/scala3demo2/target/scala-3.3.3/classes:/home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar:/home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.3.3/scala3-library_3-3.3.3.jar org.public_domain.main
Теперь его можно сократить до
$ cd /path/to/yourproject/target/scala-3.3.3/classes
$ java -classpath .:/path_to_jars/scala-library-2.13.12.jar:/path_to_jars/scala3-library_3-3.3.3.jar org.public_domain.main
Hello World!
Хотя я ценю ваш подробный ответ, он не решает основную проблему, которую я выявил (нажав на зеленую стрелку и выбрав «Выполнить» из Intellij). Однако это подтверждает вывод, к которому я предварительно пришел после посещения класса Main
в Скасти; то есть плагин IntelliJ Scala неправильно вызывает org.public_domain.main
, а не правильно org.public_domain.Main.main
.
Ах. Я только что увидел ваше переименование предложения метода main
. И ЭТО решает проблему.
@chaotic3quilibrium Итак, вы используете Windows или MacOS
Вы правильно догадались, что я на Windows.
Я не понимаю, откуда взялся main.class
. Я понимаю Main.class
и Main$.class
. Однако main
— это метод в Main
, а не класс. Итак, что именно происходит за аннотацией @main
? Генерирует ли он скрытый вложенный main
класс Scala, как следует из вашего последнего снимка экрана? Если так, то даже с моим нынешним обширным опытом работы со Scala я бы ни за что не догадался об этом.
Кстати, в версии IntelliJ, которую я использую в Windows, у меня нет sbt в Терминале (генерирует странную ошибку). Вместо этого мне приходится использовать вкладку «оболочка sbt», доступную в нижней части панели (рядом с Git, «Выполнить», «Профилировщик», «Сборка», «Службы» и т. д.). И когда я запускаю «оболочку sbt» и жду завершения ее инициализации, команда, позволяющая заставить ее делать то, что вы делаете на терминале, — «запустить», а не «запустить sbt». Оказывается, вводить «sbt{space}» в «sbtshell» совершенно не нужно. Эта оболочка предполагает префикс «sbt{space}» для каждой введенной команды.
@chaotic3quilibrium Вы можете установить sbt вне IDE scala-sbt.org
Tysvm за это. Похоже, вы подтверждаете, что аннотация @main
на самом деле вызывает сборку и компиляцию целого класса object main
Scala в фоновом режиме. IOW, это основная причина конфликта. И именно поэтому переименование его в run
превращает его в класс object run
Scala, который создается и компилируется в фоновом режиме, что разрешает конфликт.
@chaotic3quilibrium Если вы устанавливаете sbt вне IDE, то в терминале вне IDE вы можете выполнить sbt some_command
, например sbt clean
, sbt compile
, sbt run
. Или вы можете запустить sbt в интерактивном режиме, просто нажав sbt
, и выполнить там clean
, compile
, run
. Если вы выполните sbt some_command
в терминале внутри IDE или some_command
в sbt-оболочке IDE, то IDE сможет перехватить вашу команду (IDE имеет /home/dmitin/.local/share/JetBrains/IntelliJIdea2024.1/Scala/launcher/sbt-launch.jar
при установке).
Из-за такой ерунды тем, кто начинает работать со Scala, так трудно придерживаться ее. Количество глупых технических нюансов, с которыми мне приходится сталкиваться при создании проекта Scala, по сути, меня расстраивает, поскольку я никогда полностью не попадаю в сверхпродуктивное состояние «потока». И я ОБОЖАЮ Scala и выступаю за Scala с января 2011 года.