มีความแตกต่างระหว่าง YES / NO, TRUE / FALSE และจริง / เท็จใน object-c หรือไม่?


154

คำถามง่าย ๆ จริงๆ มีความแตกต่างระหว่างค่าเหล่านี้ (และมีความแตกต่างระหว่างบูลและบูล)? ร่วมงานบอกว่าพวกเขาประเมินสิ่งที่แตกต่างกันในวัตถุประสงค์ -C แต่เมื่อผมมองไปที่ typedefs ใน h ไฟล์ของตน YES / TRUE / จริงทั้งหมดกำหนดเป็น1และ NO / FALSE / 0เท็จทั้งหมดกำหนดเป็น มีความแตกต่างจริงๆหรือ?


5
จากมุมมองในทางปฏิบัติไม่มีความแตกต่าง คุณอาจทำเทคนิคต่าง ๆ เพื่อแสดงให้เห็นถึงความแตกต่างได้ แต่โดยทั่วไปคุณจะต้องหลงทางในดินแดน
เลียน่าสนใจ

คำตอบ:


84

ไม่มีความแตกต่างในทางปฏิบัติหากคุณใช้BOOLตัวแปรเป็นบูลีน C ประมวลผลนิพจน์บูลีนโดยพิจารณาว่าพวกเขาประเมินเป็น 0 หรือไม่ 0 ดังนั้น:

if(someVar ) { ... }
if(!someVar) { ... }

หมายถึงเช่นเดียวกับ

if(someVar!=0) { ... }
if(someVar==0) { ... }

ซึ่งเป็นเหตุผลที่คุณสามารถประเมินชนิดหรือนิพจน์ดั้งเดิมเป็นการทดสอบบูลีน (รวมถึงเช่นพอยน์เตอร์) โปรดทราบว่าคุณควรทำอดีตไม่ใช่อย่างหลัง

ทราบว่ามีคือความแตกต่างถ้าคุณกำหนดค่าป้านจะเรียกว่าBOOLตัวแปรและทดสอบเพื่อหาค่าเฉพาะจึงมักใช้พวกเขาเป็นบูลีนและมีเพียงกำหนดให้พวกเขาจาก#defineค่า

ที่สำคัญอย่าทดสอบบูลีนโดยใช้การเปรียบเทียบตัวละคร - มันไม่เพียงมีความเสี่ยงเพราะsomeVarสามารถกำหนดค่าที่ไม่ใช่ศูนย์ซึ่งไม่ใช่ YES แต่ในความคิดของฉันสำคัญกว่านั้นคือไม่สามารถแสดงเจตนาได้อย่างถูกต้อง:

if(someVar==YES) { ... } // don't do this!
if(someVar==NO ) { ... } // don't do this either!

กล่าวอีกนัยหนึ่งให้ใช้การสร้างตามที่ตั้งใจและจัดทำเอกสารเพื่อนำไปใช้และคุณจะช่วยตัวเองให้พ้นจากโลกแห่งความเจ็บปวดในซี


100

ฉันเชื่อว่ามี คือความแตกต่างระหว่างboolและBOOLตรวจสอบหน้าเว็บนี้เพื่ออธิบายว่าทำไม:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

เพราะBOOLเป็นunsigned charมากกว่าชนิดดั้งเดิมตัวแปรชนิดBOOLสามารถมีค่าอื่น ๆ กว่าและYESNO

พิจารณารหัสนี้:

BOOL b = 42;

if (b) {
    printf("b is not NO!\n");
}

if (b != YES) {
    printf("b is not YES!\n");
}

ผลลัพธ์คือ:

b ไม่ได้ไม่ใช่!
b ไม่ใช่ใช่!

สำหรับคนส่วนใหญ่นี้เป็นความกังวลที่ไม่จำเป็น boolแต่ถ้าคุณต้องการแบบบูลจริงๆมันจะดีกว่าที่จะใช้ ฉันควรเพิ่มที่: iOS SDK โดยทั่วไปใช้ในคำจำกัดความของอินเตอร์เฟซของตนเพื่อให้เป็นข้อโต้แย้งที่จะติดกับBOOLBOOL


5
แต่โปรดทราบว่าการติดตั้ง C ดั้งเดิมไม่มีboolและด้วยเหตุนี้จึงเป็นธรรมเนียมที่จะใช้intหรือcharเป็นบูลีนบางครั้งมี #define เพื่อซ่อนความแตกต่างและบางครั้งก็ไม่ใช่ ที่จริงแล้วฉันไม่แน่ใจว่าแม้มาตรฐานปัจจุบันboolจะต้องมีการดำเนินการในลักษณะที่ป้องกันไม่ให้ตรวจสอบว่าเป็นโครงสร้างภายใน
เลียน่าสนใจ

1
แม้ว่าที่หนึ่งprintfบอกว่าโกหก ค่าของbไม่ใช่YES, มันคือ "ไม่เป็นศูนย์", ซึ่งเป็นเงื่อนไขการทดสอบ ดังนั้นคุณควรจะมีซึ่งไม่จำเป็นต้องเหมือนกับprintf("b is not zero") YESในกรณีนี้bคือทั้ง "ไม่เป็นศูนย์" และ "ไม่ใช่ใช่"
Lawrence Dol

ขอบคุณ Lawrence ฉันได้ทำการอัปเดตตามสายเหล่านั้น
Dan J

แน่นอนฉันไม่ได้รับผลลัพธ์ที่สองใน Xcode 8.2 ที่ฉันล้มเหลว
Igor Kislyuk

1
@ HotLicks ไม่มีความแตกต่างโดยธรรมชาติระหว่าง 0 ไม่ใช่ศูนย์และเท็จและจริง ตราบใดที่ค่านี้มีวัตถุประสงค์เพื่อเป็นตรรกะบูลีนมันก็จะมีอินเตอร์เฟซนี้เพื่อรักษาความเข้ากันได้ของไบนารี ปัญหาเริ่มต้นเมื่อคุณใช้ไม่ใช่บูลีนที่ดูเหมือนบูลีนเช่นฟังก์ชั่นการป้อนแอปพลิเคชันไลบรารีมาตรฐาน c หลักจะส่งกลับ 0 เมื่อสำเร็จหลาย ๆ ท้ายคิดว่า 0 นี้เป็นบูลีนเมื่อในความเป็นจริงแล้ว มูลค่าซึ่งคาดว่ามักจะไม่ใช่ศูนย์ในการเลิกจ้างที่ผิดปกติ
Dmitry

52

ฉันทำการทดสอบอย่างละเอียดเกี่ยวกับเรื่องนี้ ผลลัพธ์ของฉันควรพูดเพื่อตัวเอง:

//These will all print "1"
NSLog(@"%d", true == true);
NSLog(@"%d", TRUE == true);
NSLog(@"%d", YES  == true);
NSLog(@"%d", true == TRUE);
NSLog(@"%d", TRUE == TRUE);
NSLog(@"%d", YES  == TRUE);
NSLog(@"%d", true == YES);
NSLog(@"%d", TRUE == YES);
NSLog(@"%d", YES  == YES);

NSLog(@"%d", false == false);
NSLog(@"%d", FALSE == false);
NSLog(@"%d", NO    == false);
NSLog(@"%d", false == FALSE);
NSLog(@"%d", FALSE == FALSE);
NSLog(@"%d", NO    == FALSE);
NSLog(@"%d", false == NO);
NSLog(@"%d", FALSE == NO);
NSLog(@"%d", NO    == NO);


//These will all print "0"
NSLog(@"%d", false == true);
NSLog(@"%d", FALSE == true);
NSLog(@"%d", NO    == true);
NSLog(@"%d", false == TRUE);
NSLog(@"%d", FALSE == TRUE);
NSLog(@"%d", NO    == TRUE);
NSLog(@"%d", false == YES);
NSLog(@"%d", FALSE == YES);
NSLog(@"%d", NO    == YES);

NSLog(@"%d", true == false);
NSLog(@"%d", TRUE == false);
NSLog(@"%d", YES  == false);
NSLog(@"%d", true == FALSE);
NSLog(@"%d", TRUE == FALSE);
NSLog(@"%d", YES  == FALSE);
NSLog(@"%d", true == NO);
NSLog(@"%d", TRUE == NO);
NSLog(@"%d", YES  == NO);

ผลลัพธ์คือ:

2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.072 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.076 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.082 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.091 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.092 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.097 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.098 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.101 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0

3
[[NSObject] alloc] init] ไม่เท่ากับ TRUE หรือ YES ดังนั้นการทดสอบการเริ่มต้นวัตถุด้วยถ้า ([[NSObject] alloc] init] == ​​TRUE) จะล้มเหลว ฉันไม่เคยพอใจกับภาษาที่กำหนดค่า "จริง" เป็นเอกพจน์เมื่อใดก็ตามที่จริงแล้วค่าที่ไม่ใช่ศูนย์จะทำ
DrFloyd5

3
@SamuelRenkert ผมไม่เคยสบายกับภาษาการค่าที่ไม่ใช่บูลีนในหรือif whileเช่น ... while("guitar gently weeps")ไม่ควรใช้ ...
Supuhstar

@SamuelRenkert ยังเป็นแบ็คอัพลีนุกซ์ที่พบในปี 2003:if (user_id = ROOT_UID)
Supuhstar

14

คุณอาจต้องการอ่านคำตอบของคำถามนี้ โดยสรุปใน Objective-C (จากคำนิยามใน objc.h):

typedef signed char        BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#define OBJC_BOOL_DEFINED


#define YES             (BOOL)1
#define NO              (BOOL)0

11

ความแตกต่างหลัก (อันตราย!) ระหว่างtrueและYESอยู่ในการทำให้เป็นอันดับ JSON

ตัวอย่างเช่นเรามีคำขอเซิร์ฟเวอร์ประเภท JSON และต้องส่งจริง / เท็จใน json sence:

NSDictionary *r1 = @{@"bool" : @(true)};
NSDictionary *r2 = @{@"bool" : @(YES)};
NSDictionary *r3 = @{@"bool" : @((BOOL)true)};

จากนั้นเราแปลงเป็นสตริง JSON ก่อนส่งเป็น

NSData *data = [NSJSONSerialization  dataWithJSONObject:requestParams options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

ผลที่ได้คือ

jsonString1 // {"bool":1}
jsonString2 // {"bool":true}
jsonString3 // {"bool":true}

เนื่องจากเหตุผลของ API jsonString1อาจทำให้เกิดข้อผิดพลาด

ดังนั้นระวังด้วย booleans ใน Objective-C

เพื่อสรุปผลเท่านั้นที่แน่นอน@YESและความคุ้มค่าหล่อเป็น@((BOOL)expression)อยู่ของ__NSCFBooleanชนิดและแปลงให้trueกับ JSON อนุกรม นิพจน์อื่น ๆ เช่น@(expression1 && expression2)(คู่@(YES && YES)) มี__NSCFNumber (int)ประเภทและแปลงเป็น1ใน JSON

PS คุณสามารถใช้บูลีนที่มีค่าเป็นสตริงได้

@{@"bool" : @"true"}; // in JSON {"bool":true}

1

มีข้อบกพร่องเล็กน้อยที่ไม่มีใครพูดถึงที่นี่ฉันคิดว่าฉันจะรวม ... ข้อผิดพลาดเชิงตรรกะมากกว่าอะไร:

int i = 2;
if(i);        //true
if(i==YES);   // false
if((!!i)==YES); //true

ดังนั้นปัญหาตรงนี้ก็คือ (YES==1)และใน C การเปรียบเทียบไม่ใช่บูลีน แต่เป็นค่าที่อิงตามค่า

เพราะYESเป็นเพียงแค่#define(มากกว่าสิ่งที่อยู่ภายในภาษา) มันจะต้องมีค่าบางอย่างและ1ทำให้รู้สึกมากที่สุด


นี่เป็นคำตอบเดียวกับ DanJ's จาก 2+ ปีก่อนโดยมีรายละเอียดน้อยลง
Lawrence Dol

@ ลอเรนซ์ดอลฉันไม่รู้ว่ามันระบุว่า YES เป็นเพียง #defined ให้เป็น 1 เท่านั้นและไม่เป็นภาษาที่แท้จริงเพราะมันอาจจะเป็นภาษาระดับสูงกว่า ... บางคนอาจได้รับคุณค่าจากสิ่งนั้น ... แต่ดี หลอกด้วยยา
ผู้เล่น Grady ผู้เล่น

0

ฉันคิดว่าพวกเขาเพิ่ม YES / NO เพื่ออธิบายตนเองได้ดีขึ้นในหลายกรณี ตัวอย่างเช่น:

[button setHidden:YES];

ฟังดูดีกว่า

[button setHidden:TRUE];

2
ฉันไม่เห็นด้วย; พวกเขาทั้งสองอ่านแบบเดียวกันกับฉัน อย่างไรก็ตามใน UI สำหรับคนธรรมดาฉันคิดว่าใช่ / ไม่ใช่ดูดีกว่า
Lawrence Dol

16
ฉันไม่เห็นด้วยเช่นกัน หากมีสิ่งใดมันอ่านได้ไม่ดีเนื่องจากไม่ยึดติดกับมาตรฐานที่ไม่ได้เขียนไว้ซึ่งใช้มานานหลายปีในภาษาอื่น IE เป็นตัวอย่างสำคัญของสิ่งที่เกิดขึ้นเมื่อคุณไม่ปฏิบัติตามมาตรฐานจำนวนมาก
FreeAsInBeer

1
Downvote ครึ่งหนึ่งสำหรับ 2 คำตอบที่ไม่ถูกต้องและ
Downvote

-2

ก่อนอื่นมาตรวจสอบว่าความจริงและเท็จคืออะไรและอะไรที่ให้ความหมายตั้งแต่แรก

เราสามารถสร้างโครงสร้างที่เรียกว่าถ้าเป็นแล้ว b อื่น c ในแคลคูลัสแลมบ์ดาดังต่อไปนี้:

(\ifThenElse. <use if then else>)(\a. \b. \c. a b c)

ใน JavaScript ดูเหมือนว่านี้:

(function(ifThenElse) {
    // use ifThenElse
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
});

เพื่อให้ ifElse มีประโยชน์เราต้องใช้ฟังก์ชัน "true" ที่เลือกทั้งขวาหรือซ้ายและทำในขณะที่ไม่สนใจตัวเลือกอื่นหรือฟังก์ชัน "false" ที่เลือกตัวเลือก "true" จะไม่ใช้

เราสามารถกำหนดฟังก์ชั่นเหล่านี้ได้ดังต่อไปนี้:

(\true. <use true>)(\a. \b. a) and (\false. <use false>)(\a. \b. b)

ใน JavaScript ดูเหมือนว่านี้:

(function(True) {
    // use True
})(function(a) {
     return function(b) {
         return a;
     }
});

(function(False) {
    // use True
})(function(a) {
     return function(b) {
         return b;
     }
});

ตอนนี้เราสามารถทำสิ่งต่อไปนี้

(\true. \false. \ifThenElse. \doThis. \doThat. ifThenElse true doThis doThat)
(\a. \b. a)(\a. \b. b)(\a. \b. \c. a b c)(\a. ())(\a. ())

ด้วย doThis และ doThat being (\ a. ()) เนื่องจาก lambda แคลคูลัสไม่ได้ให้บริการใด ๆ เช่นการพิมพ์ / คณิตศาสตร์ / สตริงทั้งหมดที่เราสามารถทำได้คือทำอะไรและพูดว่าเราทำมัน (และโกงในภายหลังโดยแทนที่ด้วยบริการใน ระบบของเราที่ให้ผลข้างเคียงที่เราต้องการ)

ดังนั้นเราจะเห็นสิ่งนี้ในการดำเนินการ

(function(True) {
    return (function(False) {
        return (function(ifThenElse) {
            return (function(doThis) {
                return (function(doThat) {
                    return ifThenElse(True)(doThis)(doThat);
                });
            });
        });
    })
})(function(a) {
     return function(b) {
         return a;
     }
})(function(a) {
     return function(b) {
         return b;
     }
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
})(function(a) { console.log("you chose LEFT!"); })
(function(a) {console.log("you chose RIGHT");})();

นั่นเป็นสภาพแวดล้อมที่ลึกที่สามารถทำให้ง่ายขึ้นถ้าเราได้รับอนุญาตให้ใช้อาร์เรย์ / แผนที่ / การโต้แย้ง / หรือมากกว่าหนึ่งคำสั่งเพื่อแยกออกเป็นฟังก์ชั่นหลายอย่าง แต่ฉันต้องการที่จะเก็บไว้บริสุทธิ์เท่าที่ฉันสามารถ จำกัด ตัวเอง เท่านั้น

โปรดสังเกตว่าชื่อจริง / เท็จไม่มีความสำคัญโดยธรรมชาติเราสามารถเปลี่ยนชื่อเป็นใช่ / ไม่ใช่ซ้าย / ขวาขวา / ซ้ายศูนย์ / หนึ่งแอปเปิ้ล / ส้ม มันมีความสำคัญในสิ่งที่เลือกทำมันเกิดจากชนิดของผู้เลือกเท่านั้น ดังนั้นหากพิมพ์ "ซ้าย" เรารู้ว่าตัวเลือกอาจเป็นจริงได้และจากความรู้นี้เราสามารถแนะนำการตัดสินใจของเราเพิ่มเติม

ดังนั้นเพื่อสรุป

function ChooseRight(left) {
    return function _ChooseRight_inner(right) {
        return right;
    }
}
function ChooseLeft(left) {
    return function _ChooseLeft_inner(right) {
        return left;
    }
}

var env = {
    '0': ChooseLeft,
    '1': ChooseRight,
    'false': ChooseRight,
    'true': ChooseLeft,
    'no': ChooseRight
    'yes': ChooseLeft,
    'snd': ChooseRight,
    'fst': ChooseLeft
};
var _0 = env['0'];
var _1 = env['1'];
var _true = env['true'];
var _false = env['false'];
var yes = env['yes'];
var no = env['no'];

// encodes church zero or one to boolean
function lambda_encodeBoolean(self) {
    return self(false)(true);
}
// decodes a Boolean to church zero or one
function lambda_decodeBoolean(self) {
    console.log(self, self ? env['true'] : env['false']);
    return self ? env['true'] : env['false'];
}

lambda_decodeBoolean('one' === 'two')(function() {
    console.log('one is two');
})(function() {
    console.log('one is not two');
})();

lambda_decodeBoolean('one' === 'one')(function() {
    console.log('one is one');
})(function() {
    console.log('one is not one');
})();

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.