詳解Swift(2)〜関数

2016. 06. 02
(※2016年6月2日追記:この記事は詳解 Swift(初版第1刷)を元に、Xcode 7.3.1(Swift 2.2)下における加筆・修正を行っています。(Xcode 7.3からXcode 7.3.1での変更点はありません))



CHAPTER 02 関数



●2.1 関数定義の基本


・関数定義の概要

List 2-1の関数isTriangle内の文で、elseの後の { が欠落しています。

    } else    // Expected '{' after 'else'
        return c < a + b

    } else {
        return c < a + b

またサンプルコードを入力している際の入力補完で気付くと思いますが、Swift 2以降はプレイグラウンドでも関数呼び出し時に2つ目以降の引数にラベルを付けるように統一されたようです。
(「Google ブックス/Swiftではじめる iPhoneアプリ開発の教科書 【Swift 2&Xcode 7対応】 - 森巧尚」、「Qiita/Swift で関数一つ呼ぶのに苦労した話し」、「Qiita/Swiftにおける名前付き引数」参照)

print(isTriangle(12.0, 20.0, 8.5))        // error: missing argument labels 'b:c:' in call
print(isTriangle(12.0, b: 20.0, c: 8.5))


・外部引数名

外部引数名と関数定義内での仮引数名を同じにする場合は仮引数名の前に # を付けることになっていましたが、エラーが出るようになりました。

func area(#height:Double, #width:Double) -> Double {

// '#' has been removed from Swift; double up 'height height' to make the argument label the same as the parameter name
// '#' has been removed from Swift; 'width' already has an argument label

一つ目のエラーは #height に対するもので「#height」を「height height」に修正するように、二つ目のエラーは #width に対するもので「#」を削除するようにと言われます。

これに関して「Xcode 7 Release Notes(Xcode 7.0 Release Notes/Swift/Swift Standard Library)」に、Xcode 7.0/Swift 2.0からメソッドと関数は外部引数名に同じ規則が適用されると記述があります。

「メソッドと関数は引数名に同じ規則を持ちます。"_"を与えることで外部引数名を省略することができます。さらにモデルを簡素化するため、デフォルト引数が特別な規則を持っているように、引数名を省略するための簡略表現 "#" は削除されました。

宣言
    func printFunction(str: String, newline: Bool)
    func printMethod(str: String, newline: Bool)
    func printFunctionOmitParameterName(str: String, _  newline: Bool)

呼出
    printFunction("hello", newline: true)
    printMethod("hello", newline: true)
    printFunctionOmitParameterName("hello", true)

(17218256)」


つまり、

・内部引数名と外部引数名を同じにするための「#」は使用できないので削除する
・第1引数の外部引数名はデフォルトで無し
 指定する際は明示する
 非表示にする場合の _ 指定は冗長(警告が出る)
・第2引数以降の外部引数名はデフォルトで内部引数名が自動割当
 別途指定する際は明示する
 非表示にする場合は _ を指定する

ということになるため、先のarea関数は以下のように修正することになります。
(「Qiita/Swiftの関数名と外部引数名の付け方メモ」参照)

func area(height height:Double, width:Double) -> Double {


・引数の値を処理中に変更できるようにする

List2-5 で仮引数 m と y を変数にして関数内で変更できるようにしようとしていますが、「'var' は Swift 3 で削除するため廃止になりました」と警告が出るようになりました。

8041.png

ここでは元の実引数はそのままに関数内での処理で変更するだけなので「Qiita/既存アプリの Xcode 7.3 + Swift 2.2 対応」に倣い、仮引数リスト上ではなく関数内で別の変数に入れ替えるといいでしょう。

func dayOfWeek(var m:Int, d:Int, var year y:Int = 2015) -> Int {    // 'var' parameters are deprecated and will be removed in Swift 3

func dayOfWeek(m:Int, d:Int, year y:Int = 2015) -> Int {
    var m = m, y = y

仮引数と同名の変数だと煩雑なので別名にした方がいいかもしれません。



●2.2 オーバーロード


・オーバーロードとは

List2-2のInt型引数2つで戻り値無しのmySwap関数に対し、List 2-8のBool型戻り値を持つmySwap関数をオーバーロードした場合、単純に呼び出すとエラーになります。

// List2-2
func mySwap(inout a:Int, inout b:Int) {
    let t = a; a = b; b = t
}

// List2-8
func mySwap(inout a:Int, inout b:Int) -> Bool {
    if a == b {
        return false
    }
    let t = a; a = b; b = t
    return true
}

var s = 10, t = 20
mySwap(&s, b: &t)        // error: ambiguous use of 'mySwap(_:b:)'

呼び出し行に「mySwapの不明瞭な使用」とエラーが出るとともに、2つのmySwap関数の定義が「note: found this candidate」と候補に挙げられます。

戻り値無しのmySwap関数を使用したい場合は、「Apple Developer/Swift Blog/Redefining Everything with the Swift REPL」の「Redefinition or Overload?」にあるように、後ろに「as Void」と追加することで呼び出すことができます。

mySwap(&s, b: &t) as Void
print("s=\(s), t=\(t)")        // "s=20, t=10"

また読者の多くは本書を読み進めながら逐次プレイグラウンドでコードを試していると思われますが、一つ不可解なエラーに遭遇すると思います。
List2-2、List2-7、List2-8と続けて試して行くと、List2-8の例を実行した際にエラーが出るのです。

// List2-2
func mySwap(inout a:Int, inout b:Int) {
    let t = a; a = b; b = t
}

// List2-7
func mySwap(inout a:Int, inout b:Int, inout c:Int) {
    let t = a; a = b; b = c; c = t
}

var s = 10, t = 20
var x = 1, y = 2, z = 3
mySwap(&s, b: &t) as Void
print("s=\(s), t=\(t)")        // "s=20, t=10"
mySwap(&x, b: &y, c: &z)
print("x=\(x), y=\(y), z=\(z)")        // "x=2, y=3, z=1"

func mySwap(inout a:String, inout b:String) {
    let t = a; a = b; b = t
}

// List2-8
func mySwap(inout a:Int, inout b:Int) -> Bool {
    if a == b {
        return false
    }
    let t = a; a = b; b = t
    return true
}

let flag : Bool = mySwap(&s, b: &t)        // Cannot convert value of type '()' to specified type 'Bool'
print("s=\(s), t=\(t), flag=\(flag)")        // "s=10, t=20, flag=true"

一応実行結果は意図通りに出力されますが、Bool値を返す関数mySwapを実行すると「Cannot convert value of type '()' to specified type 'Bool'」というエラーが出ます。
理由は不明ですが、このエラーはmySwap関数群の定義をひとまとめにし、その後に実行をまとめて行った場合には出ません。

// List2-2
func mySwap(inout a:Int, inout b:Int) {
    let t = a; a = b; b = t
}

// List2-7
func mySwap(inout a:Int, inout b:Int, inout c:Int) {
    let t = a; a = b; b = c; c = t
}

func mySwap(inout a:String, inout b:String) {
    let t = a; a = b; b = t
}

// List2-8
func mySwap(inout a:Int, inout b:Int) -> Bool {
    if a == b {
        return false
    }
    let t = a; a = b; b = t
    return true
}

var s = 10, t = 20
var x = 1, y = 2, z = 3
mySwap(&s, b: &t) as Void
print("s=\(s), t=\(t)")        // "s=20, t=10"
mySwap(&x, b: &y, c: &z)
print("x=\(x), y=\(y), z=\(z)")        // "x=2, y=3, z=1"

let flag : Bool = mySwap(&s, b: &t)        // エラー出ず
print("s=\(s), t=\(t), flag=\(flag)")        // "s=10, t=20, flag=true"

前節の「関数の呼び出し関係」でSwiftは前方参照について考慮する必要はないとありますし、定義と実行の前後関係でエラーが出たり出なかったりするのも不可解ですが、この問題はSwift 2.2でも発生するようです。



Google ブックス/Swiftではじめる iPhoneアプリ開発の教科書 【Swift 2&Xcode 7対応】 - 森巧尚

Qiita/Swift で関数一つ呼ぶのに苦労した話し

Qiita/Swiftにおける名前付き引数

Qiita/Swiftの関数名と外部引数名の付け方メモ

Wikipedia/ツェラーの公式

Qiita/既存アプリの Xcode 7.3 + Swift 2.2 対応

詳解 Swift 改訂版(Amazon)
 






QuietControl 30 wireless headphones
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
04 | 2017/05 | 06
Sun Mon Tue Wed Thu Fri Sat
- 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

QuietControl 30 wireless headphones
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR