Bài tập VBA về cơ bản ByVal, ByRef; Bài tập hàm con

Liên hệ QC

Hoàng Nhật Phương

Thành viên gắn bó
Tham gia
5/11/15
Bài viết
1,894
Được thích
1,214
Tôi không xem sub LocKetQua và SumTongCong đâu nhé. Nhưng trong LocKetQua ít nhất phải có ByVal sFile As String
Con chào Bác Siwtom,
Đầu năm con kính chúc Bác cùng gia đình Vạn sự như ý, An khang thịnh vượng ạ.
Ở bài này con vẫn còn mơ hồ một chút nữa giưã ByVal/ByRef , Bác chỉ chon hiểu thêm với ạ:
Nếu code:
Mã:
    ...
           Dim sKey As String
...
            For ik = 0 To dFile.Count - 1
                sKey = dFile.Keys()(ik)
                Call LocKetQua(sKey, Book, shtM12, lr, shtMau)
            Next ik
    ...
Sub LocKetQua(sFile As String,...)
Như vậy sFile không có ByVal ở đầu (theo con hiểu mặc định sẽ là ByRef nếu không khai báo ByVal/ByRef ở đầu) code không báo lỗi.
Nhưng khi chuyển như sau:
Mã:
    ...
 Dim sKey 
...
            For Each sKey In dFile.Keys
                Call LocKetQua(sKey, Book, shtM12, lr, shtMau)
            Next sKey
    ...
Code báo lỗi: ByRef argument type mismatch
Sub LocKetQua(ByVal sFile As String,...) sFile phải khai báo ByVal ở đầu như Bác chỉ ở trên.

Phải chăng là khi sử dụng sKey không còn là kiểu String ( giống với sFile As String) nữa mà do thay sang kiểu Variant, nếu đúng như vậy: ByVal sFile As String sẽ vẫn giữ được giá trị truyền vào nhưng khác với ByRef là nó sẽ đổi được kiểu khai báo của tham số truyền vào từ Variant sang String phải không ạ?
 
Lần chỉnh sửa cuối:
Giải như này hay nè, vận dụng mảng một cách uyển chuyển.
...
Trời ạ. Sử dụng mảng "uyển chuyển" hay không chưa biết. Nhưng sau khi si-quáp, a từ kiểu gì đó tự nhiên bị thành String. b nhờ được định là Double cho nên tự động ép kiểu, tuy nhiên nếu a không phải isnumeric thì ép kiểu sẽ ra "error".

Này thi 'mảng': cứ declare variant tuốt. Tham a, b nạp vào kiểu quái gì cũng được, trừ kiểu object (kẹt cái lệnh Set)
a = array(a, b)
b = a(0)
a = a(1)
 
Upvote 0
Nhưng sau khi si-quáp, a từ kiểu gì đó tự nhiên bị thành String. b nhờ được định là Double cho nên tự động ép kiểu, tuy nhiên nếu a không phải isnumeric thì ép kiểu sẽ ra "error".
Con chỉnh tiếp:
Mã:
Function Swap(ByVal a As Variant, ByVal b As Double, ByRef Sw As Variant)
    a = Array(a, b)
    b = a(0): a = a(1)
    Sw = Array(a, b)
End Function

Sub Test_Swap()
    Dim a As Variant, b As Double, ar As Variant
    a = 0.54321:      b = 0.12345
    Call Swap(a, b, ar)
    MsgBox "Ban dau:    a: " & a & " | " & "b: " & b & vbNewLine & _
           "Sau Swap:  a: " & ar(0) & " | " & "b: " & ar(1)
End Sub

1613577074205.png
 
Upvote 0
Sao không tận dụng Function bỏ luôn tham số Sw và thay bằng Swap = Array(a,b)
Cảm ơn Bạn đã quan tâm, do kiến thức OT hạn hẹp nên cũng không nghĩ đến, theo gợi ý của bạn thì OT viết như sau:
Mã:
Function Swap(ByVal a As Variant, ByVal b As Double) 
    a = Array(a, b)
    b = a(0): a = a(1)
    Swap = Array(a, b)
End Function

Sub test_Swap()
    Dim a As Variant, b As Double, ar As Variant
    a = 0.54321:      b = 0.12345
    ar = Swap(a, b)
    MsgBox "Ban dau:    a: " & a & " | " & "b: " & b & vbNewLine & _
               "Sau Swap:  a: " & ar(0) & " | " & "b: " & ar(1)
End Sub
Nhưng liên quan đến việc phân biệt giữa ByVal, ByRef OT thấy bài 42 vẫn thích hợp hơn.
 
Upvote 0
Hehe, tại nhìn thấy mảng đẹp mắt mà lại có lực.
Cháu đang ngân ngơ theo cái này mà chưa ra, với điều kiện không dùng biến trung gian.
Mã:
Sub HoanVi(a As Object, b As Object)
    
End Sub
Bài đã được tự động gộp:

a = array(a, b)
b = a(0)
a = a(1)
Mã:
Sub HoanVi1(A, B)
    A = Array(A, B)
    B = A(LBound(A))
    A = A(UBound(A))
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Mã:
Sub check()
    Dim r1 As Range
    Dim r2 As Sheet2
    Set r1 = Range("R1")
    Set r2 = Sheet2
    HoanVi r1, r2
    MsgBox "r1:" & r1.Address & vbNewLine & "r2:" & r2
End Sub
Sub HoanVi(A As Object, B As Object)
   Dim c As Object
   Set c = A
   Set A = B
   Set B = c
   MsgBox "Hoan vi da xong."
End Sub

Code trên chạy bị lỗi, nhưng cháu không lý giải được tại sao nó lỗi. Khi chạy thì có hiện thông báo "Hoav vi da xong.", bấm nút ok thì bị báo lỗi.
 
Upvote 0
kiến thức OT hạn hẹp nên cũng không nghĩ đến,

Mấy bài trước kêu hiểu rồi nhưng đến đây lại khiêm tốn thế.

Khi nào nắm chắc tầm vực của biến (tính chất "có thể thấy được" và tính chất "tồn tại") thì lúc đó mới áp dụng ByVal, ByRef nhanh được.
Kế đó mới rõ được 2 câu dưới này.

1613579961647.png

ByRef thường dùng trong Sub hơn.
Nếu dùng ByRef trong Function thì ngoài việc lấy trị chính gán vào tên Function, dùng thêm ByRef cho biến ngoại để lấy trị phụ.

Về lý thuyết nếu nắm được bài 4 và 9 cũng có thể nói là tạm biết dùng ByVal, ByRef, Sub/Function con, bố mẹ...

Ghi chú: Nội dung lý thuyết trong các bài cơ bản đều là những kiến thức mà anh "nhiều chữ" ở trên hướng dẫn :p

1613580399074.png
 
Upvote 0
Mã:
Sub check()
    Dim r1 As Range
    Dim r2 As Sheet2
    Set r1 = Range("R1")
    Set r2 = Sheet2
    HoanVi r1, r2
    MsgBox "r1:" & r1.Address & vbNewLine & "r2:" & r2
End Sub
Sub HoanVi(A As Object, B As Object)
   Dim c As Object
   Set c = A
   Set A = B
   Set B = c
   MsgBox "Hoan vi da xong."
End Sub

Code trên chạy bị lỗi, nhưng cháu không lý giải được tại sao nó lỗi. Khi chạy thì có hiện thông báo "Hoav vi da xong.", bấm nút ok thì bị báo lỗi.
Hoán vị xong thì r1 = Sheet2 nên lỗi đoạn code r1.Address
 
Upvote 0
Mấy bài trước kêu hiểu rồi nhưng đến đây lại khiêm tốn thế.

Khi nào nắm chắc tầm vực của biến (tính chất "có thể thấy được" và tính chất "tồn tại") thì lúc đó mới áp dụng ByVal, ByRef nhanh được.
Kế đó mới rõ được 2 câu dưới này.

View attachment 254232

ByRef thường dùng trong Sub hơn.
Nếu dùng ByRef trong Function thì ngoài việc lấy trị chính gán vào tên Function, dùng thêm ByRef cho biến ngoại để lấy trị phụ.

Về lý thuyết nếu nắm được bài 4 và 9 cũng có thể nói là tạm biết dùng ByVal, ByRef, Sub/Function con, bố mẹ...

Ghi chú: Nội dung lý thuyết trong các bài cơ bản đều là những kiến thức mà anh "nhiều chữ" ở trên hướng dẫn :p

Cảm ơn Bạn nhiều @befaint
Danh mục các bài viết đó của Bạn thi thoảng OT vẫn thường vào xem (trước đây xem vài lần chưa hiểu nhưng giờ xem lại thấy hiểu dần chút chút) đúng là rất bổ ích, nhưng do chưa có điều kiện luyện tập và va chạm nên chưa hiểu rõ Bạn ạ.
Tiện đây OT cũng đề xuất nếu có thể bạn giới thiệu thêm đôi chút về các vòng lặp for, do, hoặc if, select case.. nữa thì đầy đủ tư liệu hơn cho những người chậm hiểu như OT vì thi thoảng OT vẫn phải tìm kiếm các vấn đề liên quan đến kiến thức này..
 
Upvote 0
Hoán vị xong thì r1 = Sheet2 nên lỗi đoạn code r1.Address
Mã:
Sub check()
    Dim r1 As Range
    Dim r2 As Sheet2
    Set r1 = Range("R1")
    Set r2 = Sheet2
    HoanVi r1, r2
    
    
    MsgBox "ahihi"
End Sub
Sub HoanVi(A As Object, B As Object)
   Dim c As Object
   Set c = A
   Set A = B
   Set B = c
   MsgBox "Hoan vi da xong."
End Sub
Sửa code lại và chạy thì vẫn bị lỗi, lỗi type gì gì đó.
 
Upvote 0
Tiện đây OT cũng đề xuất nếu có thể bạn giới thiệu thêm đôi chút về các vòng lặp for, do, hoặc if, select case.. nữa thì đầy đủ tư liệu hơn cho những người chậm hiểu như OT vì thi thoảng OT vẫn phải tìm kiếm các vấn đề liên quan đến kiến thức này..
Bài 7 .
 
Upvote 0
Mã:
Sub check()
    Dim r1 As Range
    Dim r2 As Sheet2
    Set r1 = Range("R1")
    Set r2 = Sheet2
    HoanVi r1, r2
   
   
    MsgBox "ahihi"
End Sub
Sub HoanVi(A As Object, B As Object)
   Dim c As Object
   Set c = A
   Set A = B
   Set B = c
   MsgBox "Hoan vi da xong."
End Sub
Sửa code lại và chạy thì vẫn bị lỗi, lỗi type gì gì đó.
Thử chỉnh code theo như vậy rồi test thử xem
PHP:
Sub Test()
  Dim A, B
  A = 100
  Set B = New Collection
  HoanVi A, B
  Stop
End Sub

Sub HoanVi(A, B)
  Dim C: C = Array(A, B)
  TaoBanSao B, C(0)
  TaoBanSao A, C(1)
End Sub

Sub TaoBanSao(A, A1)
  If IsObject(A1) Then
    Set A = A1
  Else
    A = A1
  End If
End Sub
 
Upvote 0
VBA không phải là ngôn ngữ có khả năng hướng đối tượng.
Vì thế, biết sử dụng được Objects là tốt rồi, đừng có nghĩ đến chuyện hoán trị Objects.
Công việc đó liên quan đến biến tham chiếu (*1), rất dễ bị rò bộ nhớ, và rất dễ sai.

Ở bài #41 tôi chỉ nói ra cái gì được và cái gì không được thôi. Để thì giờ và tâm trí học tập những điều khác hiệu quả hơn.

Cũng như việc hoán trị không qua biến tạm. Đối với một số ngôn ngữ có khả năng 'piping', người ta dùng cách này để có thể viết tất cả các lệnh gom về một dòng và gói gọn thành hàm trực tiếp (*2). VBA không có klhar năng này cho nên công việc 'giảm số biến' chỉ là trò chơi cho vui thôi.

(*1) cái này dân chuyên LTHĐT dùng nó để thể hiện tínhn đa hình (metamorphism). Cỡ nhơn vật "$200 một tiết C++" chưa chắc biết dùng.

(*2) điển hình macro trong C hoặc inline fucntion trong C++
a += b -= a = b - a; // cộng và trừ (piping values). Hoặc
(a ^= b), (b ^= a), (a ^= b); // bit xor vàv toán tử , (dấu phẩy)
Những ngôn ngữ có thư viện làm việc với dataset thì có lệnh làm thẳng luôn. Ví dụ Python:
x, y = y, x
 
Upvote 0
Mã:
Sub check()
    Dim r1 As Range
    ...
End Sub
Sửa code lại và chạy thì vẫn bị lỗi, lỗi type gì gì đó.

Msgbox chạy vì code sub Hoanvi không lỗi, Hoanvi không lỗi vì khai báo A, B là Variant.

Msgbox xong quay về sub Test mới lỗi trên sub Test. Sub Test lỗi vì khai báo r1 = range sau đó bị đổi thành sheet. Chẳng phải Type Mismatch thì là gì bây giờ
 
Upvote 0
Upvote 0
Dạ, cháu chữ nghĩ tới đoạn này, cảm ơn bác vì đã bật bí.hihi
Chủ yếu là đọc thông báo lỗi, dò code lỗi xem đã chạy tới đâu, câu lệnh nào bị lỗi, ...
Như ví dụ trên thì ngay từ range chuyển sang sheet đã lỗi rồi có đâu mà đến câu lệnh .Address
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom