🎯
Dart Enum . 記法の使い所
Swiftみたいに省略記法があった!
SwiftのEnumには、.を使って定数を呼び出す記法があるのですが、Dartにはないのかなと思っていたら、あった😅
強強モバイルエンジニアたっつーさんに教えていただきました🙇
本当にあったよ(°_°)
enum LogLevel { debug, info, warning, error }
/// Returns the color code to use for the specified log [level].
String colorCode(LogLevel level) {
// Use dot shorthand syntax for enum values in switch cases:
return switch (level) {
.debug => 'gray', // Instead of LogLevel.debug
.info => 'blue', // Instead of LogLevel.info
.warning => 'orange', // Instead of LogLevel.warning
.error => 'red', // Instead of LogLevel.error
};
}
// Example usage:
String warnColor = colorCode(.warning); // Returns 'orange'
以前だと
昔からある方法。
final appBarColor = switch (_selectedLevel) {
LogLevel.debug => Colors.grey,
LogLevel.info => Colors.blue,
LogLevel.warning => Colors.orange,
LogLevel.error => Colors.red,
};
.で省略すると...
短くなった!
final appBarColor = switch (_selectedLevel) {
.debug => Colors.grey,
.info => Colors.blue,
.warning => Colors.orange,
.error => Colors.red,
};
こちらの本にも使い方解説しております👇
🤔活用例を考える❓
公式がログレベルのサンプルコードを出していたのでログレベルを表示するソースコードを考えてみた。といっても自分で全部やったわけではなくClaudeCode + Flutter & Dart MCP Serverを活用しました。こっちの方が綺麗なコード書いてくれたので😅
こちらがデモ
sample
main.dart
import 'package:flutter/material.dart';
enum LogLevel { debug, info, warning, error }
/// Record型でログレベルの表示情報を返す
/// Dart 3.0 switch式の `.` shorthand を使用(swift caseは不使用)
({Color color, IconData icon, String title, String message, Color? bg}) levelInfo(LogLevel level) {
return switch (level) {
.debug => (
color: Colors.grey,
icon: Icons.bug_report,
title: 'Debug Mode',
message: 'Detailed logs enabled for debugging.',
bg: null,
),
.info => (
color: Colors.blue,
icon: Icons.info,
title: 'Info',
message: 'General information about app state.',
bg: null,
),
.warning => (
color: Colors.deepOrange,
icon: Icons.warning_amber_rounded,
title: 'Warning',
message: 'Something needs attention.',
bg: Colors.orange.shade100,
),
.error => (
color: Colors.red,
icon: Icons.error_outline,
title: 'CRITICAL ERROR',
message: 'Immediate action required!',
bg: Colors.red.shade50,
),
};
}
/// ログレベルに応じたWidgetを返す(switch式でWidget自体を切り替え)
Widget buildLogWidget(LogLevel level) {
final info = levelInfo(level);
return switch (level) {
.debug => _DebugWidget(info: info),
.info => _InfoWidget(info: info),
.warning => _WarningWidget(info: info),
.error => _ErrorWidget(info: info),
};
}
/// Debug用Widget
class _DebugWidget extends StatelessWidget {
final ({Color color, IconData icon, String title, String message, Color? bg}) info;
const _DebugWidget({required this.info});
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(info.icon, size: 80, color: info.color),
const SizedBox(height: 16),
Text(
info.title,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: info.color),
),
Text(info.message, style: TextStyle(color: Colors.grey.shade600)),
],
);
}
}
/// Info用Widget
class _InfoWidget extends StatelessWidget {
final ({Color color, IconData icon, String title, String message, Color? bg}) info;
const _InfoWidget({required this.info});
Widget build(BuildContext context) {
return Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(info.icon, size: 60, color: info.color),
const SizedBox(height: 12),
Text(
info.title,
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: info.color),
),
const SizedBox(height: 8),
Text(info.message),
],
),
),
);
}
}
/// Warning用Widget
class _WarningWidget extends StatelessWidget {
final ({Color color, IconData icon, String title, String message, Color? bg}) info;
const _WarningWidget({required this.info});
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: info.bg,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.orange, width: 2),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(info.icon, size: 40, color: info.color),
const SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
info.title,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: info.color),
),
Text(info.message, style: TextStyle(color: info.color)),
],
),
],
),
);
}
}
/// Error用Widget
class _ErrorWidget extends StatelessWidget {
final ({Color color, IconData icon, String title, String message, Color? bg}) info;
const _ErrorWidget({required this.info});
Widget build(BuildContext context) {
return Card(
elevation: 8,
color: info.bg,
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(info.icon, size: 60, color: info.color),
const SizedBox(height: 16),
Text(
info.title,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: info.color),
),
const SizedBox(height: 8),
Text(info.message, style: TextStyle(color: info.color)),
],
),
),
);
}
}
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(home: LogLevelDemoView());
}
}
class LogLevelDemoView extends StatefulWidget {
const LogLevelDemoView({super.key});
State<LogLevelDemoView> createState() => _LogLevelDemoViewState();
}
class _LogLevelDemoViewState extends State<LogLevelDemoView> {
LogLevel _selectedLevel = LogLevel.info;
Widget build(BuildContext context) {
// switch式でAppBarの色を取得
final appBarColor = switch (_selectedLevel) {
.debug => Colors.grey,
.info => Colors.blue,
.warning => Colors.orange,
.error => Colors.red,
};
return Scaffold(
appBar: AppBar(
title: const Text('Log Level Switcher'),
backgroundColor: appBarColor,
foregroundColor: Colors.white,
),
body: Column(
children: [
Expanded(
child: Center(
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: KeyedSubtree(
key: ValueKey(_selectedLevel),
child: buildLogWidget(_selectedLevel),
),
),
),
),
Container(
padding: const EdgeInsets.all(16.0),
color: Colors.grey.shade100,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Select Log Level:',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
Wrap(
alignment: WrapAlignment.center,
spacing: 10,
runSpacing: 10,
children: LogLevel.values.map((level) {
final isSelected = _selectedLevel == level;
final buttonColor = levelInfo(level).color;
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: isSelected ? buttonColor : Colors.white,
foregroundColor: isSelected ? Colors.white : buttonColor,
side: BorderSide(color: buttonColor),
elevation: isSelected ? 2 : 0,
),
onPressed: () {
setState(() {
_selectedLevel = level;
});
},
child: Text(level.name.toUpperCase()),
);
}).toList(),
),
],
),
),
],
),
);
}
}
最後に
省略記法の.があると今の参画してる案件でFlutterに強いエンジニアさんから教わったのですが本当にあったとは。。。
SwiftのEnumみたいにSwitchのところで、.の省略記法が使えるのは有り難かった!
SwiftのEnum .が気になる方いたらこちら見てみてください👀
directionToHead の型は、CompassPoint の取りうる値のいずれかで初期化されるときに推論されます。一度 directionToHead が CompassPoint として宣言されると、より短いドット構文を使って別の CompassPoint の値に設定できます。
directionToHead = .east
directionToHead の型はすでに判明しているため、その値を設定する際に型名を省略できます。これにより、明示的に型指定された列挙値を使用するコードは非常に読みやすくなります。
Switch文による列挙値のマッチング
個々の列挙値をswitch文で照合できます。
directionToHead = .south
switch directionToHead {
case .north:
print("Lots of planets have a north")
case .south:
print("Watch out for penguins")
case .east:
print("Where the sun rises")
case .west:
print("Where the skies are blue")
}
// Prints "Watch out for penguins".
Discussion