ãã®æçš¿ã¯ã Swift vs.ã®ç¡æ翻蚳ã§ãã Kotlin- Krzysztof Turekã«ããéèŠãªéã
ãããããSwiftãšKotlinã®ãã®æ¯èŒãèŠãŸããïŒ http : //nilhcem.com/swift-is-like-kotlin/ ããªãé¢çœãã§ããã ãããã®èšèªã«ã¯å€ãã®é¡äŒŒç¹ãããããšã«åæããŸããããã®èšäºã§ã¯ãããã«ããããããããããç°ãªããã®ã«ããããã€ãã®åŽé¢ã«æ³šæãæããŸãã
2013幎ããAndroidéçºã«æºãããã»ãšãã©ã®æéã§Javaã¢ããªã±ãŒã·ã§ã³ãéçºããŠããŸãã æè¿ãiOSãšSwiftãè©Šãæ©äŒãåŸãŸããã Swiftã§éåžžã«ã¯ãŒã«ãªã³ãŒããæžãããšãå€æãããšããäºå®ã«æéãåããŸããã åªåããã°ãã³ãŒãã¯è©©ã®ããã«èŠããŸãã
7ãæåŸãAndroidã«æ»ããŸããã ããããJavaã®ä»£ããã«ãKotlinã§ã³ãŒãã£ã³ã°ãéå§ããŸããã Googleã¯Google IO 2017ã§ãKotlinãAndroidã®å
¬åŒèšèªã«ãªã£ãããšãçºè¡šããŸããã ãããŠç§ã¯åœŒã«æããããšã«ããŸããã KotlinãšSwiftã®é¡äŒŒç¹ã«æ°ä»ãã®ã«ããã»ã©æéã¯ããããŸããã§ããã ããããããããéåžžã«äŒŒãŠãããšã¯èšããŸããã 以äžã«ããããã®éãã瀺ããŸãã ãã¹ãŠã説æããã®ã§ã¯ãªããèå³ã®ãããã®ã ãã説æããŸãã ããã€ãã®äŸãèŠãŠã¿ãŸãããã
æ§é 察 ããŒã¿ã¯ã©ã¹ã å€ãšåç
§
æ§é äœãšããŒã¿ã¯ã©ã¹ã¯ãã¯ã©ã¹ã®ç°¡æããŒãžã§ã³ã§ãã 䜿çšæ¹æ³ã¯äŒŒãŠããŸããããã®ããã«èŠããŸã
ã³ããªã³ïŒ
data class Foo(var data: Int)
ã¹ã€ããïŒ
struct Foo { var data: Int }
ããããã¯ã©ã¹ã¯ãŸã ã¯ã©ã¹ã§ãã ãã®åã¯åç
§æž¡ããããŸãã ããããæ§é -å€ã«ãã£ãŠã ãã ããäœïŒã ãé¡ãããŸãã äŸã§èª¬æããŸãã
Kotlinã§ããŒã¿ã¯ã©ã¹ãäœæããSwiftã§æ§é ãäœæããŠãçµæãæ¯èŒããŸãããã
ã³ããªã³ïŒ
var foo1 = Foo(2) var foo2 = foo1 foo1.data = 4
ã¹ã€ããïŒ
var foo1 = Foo(data: 2) var foo2 = foo1 foo1.data = 4
äž¡æ¹ã®ã±ãŒã¹ã§çããfoo2ã®ããŒã¿ã¯äœã§ããïŒ KotlinããŒã¿ã¯ã©ã¹ã®å Žåã¯4ãSwiftæ§é äœã®å Žåã¯2ã§ãã
Swiftã®var foo2 = foo1ã¯æ§é ã€ã³ã¹ã¿ã³ã¹ã®ã³ããŒãäœæãïŒè©³çŽ°ã¯ãã¡ã ïŒãKotlinã§ã¯åããªããžã§ã¯ããžã®ãã1ã€ã®ãªã³ã¯ïŒè©³çŽ°ã¯ãã¡ã ïŒã§ãããããçµæã¯ç°ãªããŸã
Javaã䜿çšããŠããå Žåã¯ãããããé²åŸ¡ã³ããŒãã¿ãŒã³ã«ç²ŸéããŠããã§ãããã ããã§ãªãå Žåãè¿œãã€ããŸãã ããã§ããããã¯ã«é¢ãã詳现æ
å ±ãèŠã€ããããšãã§ããŸãã
äžè¬çã«ããªããžã§ã¯ãã®ç¶æ
ãå
åŽãŸãã¯å€åŽããå€æŽããããšãå¯èœã§ãã æåã®ãªãã·ã§ã³ãæãŸãããããäžè¬çã§ããã2çªç®ã®ãªãã·ã§ã³ã¯ããã§ã¯ãããŸããã ç¹ã«ãåç
§åã䜿çšããŠããŠããã®ç¶æ
ã®å€åãæåŸ
ããªãå Žåã ããã«ããããã°ã®æ€çŽ¢ãè€éã«ãªãå¯èœæ§ããããŸãã ãã®åé¡ãé²ãã«ã¯ãä»ã®å Žæã«è»¢éããåã«ãå€æŽå¯èœãªãªããžã§ã¯ãã®å®å
šãªã³ããŒãäœæããå¿
èŠããããŸãã ãã®ãããªç¶æ³ã§ã¯ãKotlinã¯Javaãããã¯ããã«äŸ¿å©ã§ãããäžæ³šæã¯äŸç¶ãšããŠåé¡ãåŒãèµ·ããå¯èœæ§ããããŸãã ç°¡åãªäŸãèããŠã¿ãŸãããã
data class Page(val title: String) class Book { val pages: MutableList<Page> = mutableListOf(Page(âChapter 1â), Page(âChapter 2â)) }
ãã®ãªããžã§ã¯ãå
ã§ããŒãžãå€æŽïŒè¿œå ãåé€ãªã©ïŒãããã®ã§ã ããŒãžãMutableListãšããŠå®£èšããŸããã å€éšããããŒãžã®ç¶æ
ã«ã¢ã¯ã»ã¹ããå¿
èŠãããããã ããŒãžã¯ ãã©ã€ããŒãã§ã¯ãããŸããã ãããŸã§ã®ãšããããã¹ãŠãé 調ã«é²ãã§ããŸãã
val book = Book() print(â$bookâ) // Book(pages=[Page(title=Chapter 1), Page(title=Chapter 2)])
ããã§ãæ¬ã®çŸåšã®ç¶æ
ã«ã¢ã¯ã»ã¹ã§ããŸãã
val bookPages = book.pages
bookPagesã«æ°ããããŒãžãè¿œå ããŠããŸãïŒ
bookPages.add(Page(âChapter 3â))
æ®å¿µãªããããœãŒã¹ããã¯ã®ç¶æ
ãå€æŽããŸããã ãããŠãããã¯ç§ãæãã§ãããã®ã§ã¯ãããŸããã
print(â$bookâ) // Book(pages=[Page(title=Chapter 1), Page(title=Chapter 2), Page(title=Chapter 3)])
å®å
šãªã³ããŒã䜿çšããŠãããåé¿ã§ããŸãã Kotlinã§ã¯éåžžã«ç°¡åã§ãã
book.pages.toMutableList()
ä»ã§ã¯ãã¹ãŠãé 調ã§ãã :)
ããããSwiftã¯ã©ãã§ããïŒ ãã¹ãŠãç®±ããåºããŠåäœããŸãã ã¯ããé
åã¯æ§é äœã§ãã åè¿°ã®ããã«ãæ§é ã¯å€ã«ãã£ãŠæž¡ãããããã次ã®ããã«èšè¿°ããŸãã
var bookPages = book.pages
ããŒãžãªã¹ãã®ã³ããŒã䜿çšããŠããŸãã
ãããã£ãŠãå€ã«ããããŒã¿ã®éä¿¡ãæ±ã£ãŠããŸãã ãããã°äžã«é çãçµéšããããªãå Žåãããã¯éããç解ããããã«éåžžã«éèŠã§ãã :) IntãCGPointãArrayãªã©ãå€ãã®ããªããžã§ã¯ããã¯Swiftã®æ§é ã§ãã
ã€ã³ã¿ãŒãã§ã€ã¹ãšãããã³ã«ããã³æ¡åŒµæ©èœ
ããã¯ç§ã®ãæ°ã«å
¥ãã®ãããã¯ã§ãã ïŒD
ã€ã³ã¿ãŒãã§ãŒã¹ãšãããã³ã«ãæ¯èŒããããšããå§ããŸãããã ååãšããŠããããã¯åäžã§ãã
- äž¡æ¹ãšããã¯ã©ã¹/æ§é å
ã®ç¹å®ã®ã¡ãœããã®å®è£
ãå¿
èŠã«ãªãå ŽåããããŸãã
- ã©ã¡ããç¹å®ã®ããããã£ã®å®£èšãå¿
èŠãªå ŽåããããŸãã ããããã£ã¯ãèªã¿åã/æžã蟌ã¿ãŸãã¯èªã¿åãå°çšã«ã§ããŸãã
- äž¡æ¹ãšããã¡ãœããã®ããã©ã«ãã®å®è£
ãè¿œå ã§ããŸãã
ããã«ããããã³ã«ã«ã¯ç¹å®ã®åæååïŒKotlinã®ã³ã³ã¹ãã©ã¯ã¿ãŒïŒãå¿
èŠãªå ŽåããããŸãã
ã³ããªã³ïŒ
interface MyInterface { var myVariable: Int val myReadOnlyProperty: Int fun myMethod() fun myMethodWithBody() {
ã¹ã€ããïŒ
protocol MyProtocol { init(parameter: Int) var myVariable: Int { get set } var myReadOnlyProperty: Int { get } func myMethod() func myMethodWithBody() } extension MyProtocol { func myMethodWithBody() {
*ããã©ã«ãã¡ãœããã®å®è£
ããããã³ã«å
ã«çŽæ¥è¿œå ã§ããªãããšã«æ³šæããŠãã ããã ãããããªã¹ãã®æåŸã®é
ç®ã«ã¢ã¹ã¿ãªã¹ã¯ãè¿œå ããçç±ã§ãã ããã«ã¯æ¡åŒµæ©èœãè¿œå ããå¿
èŠããããŸãã ãããŠãããã¯ããèå³æ·±ãéšåã§ããæ¡åŒµæ©èœã«é²ãè¯ãæ¹æ³ã§ãïŒ
æ¡åŒµæ©èœã䜿çšãããšãæ¢åã®ã¯ã©ã¹ïŒãŸãã¯æ§é ;ïŒã«æ©èœãè¿œå ã§ããŸãããç¶æ¿ããããšã¯ã§ããŸããã ãšãŠãç°¡åã§ãã åæããŸããããã¯çŽ æŽãããæ©äŒã§ãã
ããã¯Androidéçºè
ã«ãšã£ãŠã¯æ°ãããã®ãªã®ã§ãåžžã«äœ¿çšãããã§ãïŒ Kotlinã§æ¡åŒµæ©èœãäœæããŸã-ãã±ãããå®å®ã«çºå°ããªãã§ãã ããã
ããããã£ã®æ¡åŒµæ©èœãäœæã§ããŸãã
val Calendar.yearAhead: Calendar get() { this.add(Calendar.YEAR, 1) return this }
ãŸãã¯æ©èœçšïŒ
fun Context.getDrawableCompat(@DrawableRes drawableRes: Int): Drawable { return ContextCompat.getDrawable(this, drawableRes) ?: throw NullPointerException("Can not find drawable with id = $drawableRes") }
ã芧ã®ãšãããããã§ã¯ããŒã¯ãŒãã䜿çšããŠããŸããã
Kotlinã«ã¯ããªãã·ã§ã³ã®æååã®ãorEmptyïŒïŒããªã©ãããªãã¯ãŒã«ãªå®çŸ©æžã¿ã®æ¡åŒµæ©èœãããã€ããããŸãã
var maybeNullString: String = null titleView.setText(maybeNullString.orEmpty())
ãã®äŸ¿å©ãªæ¡åŒµæ©èœã¯æ¬¡ã®ããã«ãªããŸãã
public inline fun String?.orEmpty(): String = this ?: ""
'ïŒïŒ'㯠'this'ïŒçŸåšã®æååã®å€ïŒããå€ãååŸããããšããŠããŸãã nullã®å Žåã空ã®æååãè¿ãããŸãã
ããã§ã¯ãSwiftã®æ¡åŒµæ©èœãèŠãŠã¿ãŸãããã
ãããã®å®çŸ©ã¯åãã§ãããããç§ã¯ãããã³ã°ãããã¬ã³ãŒããšããŠèªåèªèº«ãç¹°ãè¿ããŸããã
ãorEmptyïŒïŒãã®ãããªæ¡åŒµæ©èœãæ¢ããŠããå Žåãæªããã¥ãŒã¹ããããŸãã ã§ãè¿œå ã§ããŸãããïŒ ãã£ãŠã¿ãŸãããïŒ
extension String? { func orEmpty() -> String { return self ?? "" } }
ããããããã¯ããªããèŠããã®ã§ãïŒ
Swiftã®ãªãã·ã§ã³ã¯ãæå®ãããWrappedã¿ã€ãã®äžè¬çãªåæã§ãã ãã®å Žåã Wrappedã¯æååã§ãããããæ¡åŒµåã¯æ¬¡ã®ããã«ãªããŸãã
extension Optional where Wrapped == String { func orEmpty() -> String { switch self { case .some(let value): return value default: return "" } } }
ãããŠããžãã¹ã§ïŒ
let page = Page(text: maybeNilString.orEmpty())
Kotlinã®ã«ãŠã³ã¿ãŒããŒããããé£ããèŠããŸãããïŒ ãããŠãæ®å¿µãªãããæ¬ ç¹ããããŸãã ãåãã®ããã«ãSwiftã®ãªãã·ã§ã³ã¯æ±çšã®åæã§ããããããã¹ãŠã®ãªãã·ã§ã³ã¿ã€ãã§æ¡åŒµæ©èœã䜿çšã§ããŸãã ããŸãè¯ãèŠããŸããïŒ
ãã ããã³ã³ãã€ã©ãŒã¯ãŠãŒã¶ãŒãä¿è·ãããã®ã³ãŒããã³ã³ãã€ã«ããŸããã ãããããããã®æ¡åŒµæ©èœãããã«è¿œå ãããšãèªåãã«ãããŽãã§è©°ãŸã£ãŠããŸããŸãã
ããã§ã¯ãKotlinæ¡åŒµæ©èœã¯Swiftãã䟿å©ã§ããïŒ Swiftã®æ¡åŒµæ©èœã¯ä»ã®ç®çã®ããã ãšæããŸã;ïŒã Androidéçºè
ã¯ãåŸ
ã¡ãã ããïŒ
ãããã³ã«ãšæ¡åŒµæ©èœã¯ãé£æºããŠåäœããããã«èšèšãããŠããŸãã ãã®ãããã³ã«ã«æºæ ããã¯ã©ã¹ã®ç¬èªã®ãããã³ã«ãšæ¡åŒµæ©èœãäœæã§ããŸãã ã¯ã¬ã€ãžãŒã«èãããŸãããããã ãã§ã¯ãããŸããïŒ ãããã³ã«ãšã®æ¡ä»¶ä»ãã³ã³ãã©ã€ã¢ã³ã¹ãªã©ã®ãã®ããããŸã ã ããã¯ãã¯ã©ã¹/æ§é ãç¹å®ã®æ¡ä»¶äžã§ãããã³ã«ã«æºæ ã§ããããšãæå³ããŸãã
ãããã¢ããã¢ã©ãŒãã衚瀺ããå¿
èŠãããå ŽæããããããããšããŸãã DRYã®ååã¯æ°ã«å
¥ã£ãŠããŸãããã³ãŒããã³ããŒããŠè²Œãä»ããããããŸããã ãããã³ã«ãšæ¡åŒµæ©èœã䜿çšããŠãã®åé¡ã解決ã§ããŸãã
ãŸãããããã³ã«ãäœæããŸãã
protocol AlertPresentable { func presentAlert(message: String) }
次ã«ãããã©ã«ãå®è£
ã®æ¡åŒµæ©èœïŒ
extension AlertPresentable { func presentAlert(message: String) { let alert = UIAlertController(title: âAlertâ, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: âOKâ, style: .default, handler: nil)) } }
ãããã£ãŠãpresentAlertã¡ãœããã¯ã¢ã©ãŒããäœæããã ãã§ãäœã衚瀺ããŸããã ããã«ã¯ãView Controllerãžã®ãªã³ã¯ãå¿
èŠã§ãã ãã®ã¡ãœããã«ãã©ã¡ãŒã¿ãŒãšããŠæž¡ãããšã¯ã§ããŸããïŒ è¯ãèãã§ã¯ãããŸããã Whereã䜿çšããŸãããïŒ
extension AlertPresentable where Self: UIViewController { func presentAlert(message: String) { let alert = UIAlertController(title: âAlertâ, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: âOKâ, style: .default, handler: nil)) self.present(alert, animated: true, completion: nil) } }
ããã«ã¯äœããããŸããïŒ ãããã³ã«ãæ¡åŒµããããã®ç¹å®ã®èŠä»¶ãè¿œå ããŸããã UIViewControllerã®ã¿ã察象ãšããŠããŸãã ããã«ãããpresentAlertã¡ãœããã§UIViewControllerã¡ãœããã䜿çšã§ããŸãã ããã«ãããã¢ã©ãŒãã衚瀺ã§ããŸãã
ã©ãã
extension UIViewController: AlertPresentable {}
ãã¹ãŠã®UIViewControllerã«æ°ããæ©èœãè¿œå ãããŸããã
ãŸãããããã³ã«ãšæ¡åŒµæ©èœã®çµã¿åããã¯ããã¹ãã«éåžžã«åœ¹ç«ã¡ãŸãã çãããããªãã®ã¢ããªã±ãŒã·ã§ã³ã§Androidã®æçµã¯ã©ã¹ãäœåãã¹ãããããšããŸãããïŒ ããã¯Swiftã«ãšã£ãŠåé¡ã§ã¯ãããŸããã
ãã®ç¶æ³ãèŠãŠã¿ãŸããããSwiftã«finalã¯ã©ã¹ããããšä»®å®ããŸãã ã¡ãœããã®ã·ã°ããã£ãããã£ãŠããå Žåã¯ãåãã¡ãœããã§ãããã³ã«ãäœæãããã®ãããã³ã«ãå®è£
ããæ¡åŒµæ©èœãæçµã¯ã©ã¹ã«è¿œå ããŸãã ãã®ã¯ã©ã¹ãçŽæ¥äœ¿çšãã代ããã«ããããã³ã«ã䜿çšããŠç°¡åã«ãã¹ãã§ããŸãã åèªã§ã¯ãªããµã³ãã«ã³ãŒãã
final class FrameworkMap { private init() { ⊠} func drawSomething() { ⊠} } class MyClass { ⊠func drawSomethingOnMap(map: FrameworkMap) { map.drawSomething() } }
ãã¹ãã§ã¯ãdrawSomethingOnMapã¡ãœãããå®è¡ãããšãã«ãããããªããžã§ã¯ãã§drawSomethingã¡ãœãããåŒã³åºããããã©ããã確èªããå¿
èŠããããŸãã ããã¯ãMockitoïŒAndroidçšã®æåãªãã¹ãã©ã€ãã©ãªïŒã䜿çšããŠãé£ããå ŽåããããŸãã ãããããããã³ã«ãšæ¡åŒµæ©èœã䜿çšãããšã次ã®ããã«ãªããŸãã
protocol Map { func drawSomething() } extension FrameworkMap: Map {}
ãããŠä»ãããªãã®drawSomethingOnMapã¡ãœããã¯ã¯ã©ã¹ã®ä»£ããã«ãããã³ã«ã䜿çšããŸãã
class MyClass { ⊠func drawSomethingOnMap(map: Map) { map.drawSomething() } }
ã·ãŒã«ãã¯ã©ã¹-ã¹ããã€ãã®è»¢é
æåŸã«ãåæã«ã€ããŠèšåããããšæããŸãã
JavaåæãšKotlinåæã®éã«éãã¯ãªããããããã«è¿œå ãããã®ã¯ãããŸããã ããããèŠè¿ãã«äœãæ°ãããã®ãããããããã¯ãã¹ãŒããŒåæããã€ãŸãå°å°ãããã¯ã©ã¹ã§ãã ã¹ãŒããŒãªã¹ãã®æŠå¿µã¯ã©ãããæ¥ãã®ã§ããïŒ Kotlinã®ããã¥ã¡ã³ããåç
§ããŠãã ããã
ã...ããæå³ãåæã¯ã©ã¹ã®æ¡åŒµæ©èœã§ããåæã«äœ¿çšã§ããå€ã®ã»ãããå¶éãããŠããŸãããååæå®æ°ã¯åäžã®ã€ã³ã¹ã¿ã³ã¹ã«ã®ã¿ååšããŸãã ã
ããŠãã¯ãŒã«ã圌ãã¯è²¡ç£ãä¿ã€ããšãã§ããŸãããã©ã®ããã«ããã䜿çšã§ããŸããïŒ
sealed class OrderStatus { object AwaitPayment : OrderStatus() object InProgress : OrderStatus() object Completed : OrderStatus() data class Canceled(val reason: String) : OrderStatus() }
ããã¯ã泚æã¹ããŒã¿ã¹ã¢ãã«ã§ããå°å°ãããã¯ã©ã¹ã§ãã ä¹ãæãã®æ¹æ³ãšéåžžã«äŒŒãŠããŸããã泚æç¹ã1ã€ãããŸãã Canceledå€ã«ã¯ããã£ã³ã»ã«ã®çç±ãå«ãŸããŠããŸãã ãã£ã³ã»ã«ã®çç±ã¯ç°ãªãå ŽåããããŸãã
val orderStatus = OrderStatus.Canceled(reason = "No longer in stock") ⊠val orderStatus = OrderStatus.Canceled(reason = "Not paid")
éåžžã®ãªã¹ãã§ã¯ãããè¡ããŸããã åæå€ãäœæãããå Žåãå€æŽã§ããŸããã
ä»ã®éãã«æ°ã¥ããŸãããïŒ å°å°ãããã¯ã©ã¹ã®å¥ã®æ©èœãå©çšããŸããã ããã¯ãããŸããŸãªã¿ã€ãã®é¢é£ããŒã¿ã§ãã å€å
žçãªåæã«ã¯ãåæå€ã®ãã¹ãŠã®ããªã¢ã³ãã®é¢é£ããŒã¿ã®è»¢éãå«ãŸãããã¹ãŠã®å€ã¯åãã¿ã€ãã§ãªããã°ãªããŸããã
Swiftã«ã¯ã·ãŒã«ãã¯ã©ã¹ã«çžåœãããã®ããããåæãšåŒã°ããŸãã Kotlinã®åæã¯Javaã®åãªãéºç©ã§ããã90ïŒ
ã®æéã¯ã·ãŒã«ãã¯ã©ã¹ã䜿çšããŸãã ã·ãŒã«ã¯ã©ã¹ãšSwiftåæåãåºå¥ããã®ã¯å°é£ã§ãã ååã®ã¿ãç°ãªãããã¡ãããå°å°ãããã¯ã©ã¹ã¯åç
§ã«ãã£ãŠæž¡ãããSwiftã®åæã¯å€ã«ãã£ãŠæž¡ãããŸãã ç§ãééã£ãŠããå Žåã¯ä¿®æ£ããŠãã ããã
ãããªãã¯èšããªã
ã³ãŒãã®èšè¿°æ¹æ³ã«å¯Ÿããã¡ã¢ãªç®¡çã®åœ±é¿ã«ã¯ãŸã 埮åŠãªéãããããŸãã ç§ã¯ãã¹ãŠã®åŽé¢ãã«ããŒããŠããªãããšãç¥ã£ãŠããŸããããã¯ç§ããŸã å匷ããŠããããã§ãã 2ã€ã®èšèªã®éã«ä»ã®éããããããšã«æ°ã¥ããããæããŠãã ããã ç§ã¯åžžã«æ°ããããšã«ãªãŒãã³ã§ãïŒ